e58163f0ebd4c22346f01eeb1b4993c4e597dec3
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
1 /*
2  * Copyright (c) 2008 Secure Endpoints, Inc.
3  * Copyright (c) 2009-2013 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     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1583                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1584     if (code) {
1585         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1586         (*ResultCB)->ResultStatus = status;
1587         lock_ReleaseWrite(&dscp->rw);
1588         cm_ReleaseSCache(dscp);
1589         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1590                  dscp, code, status);
1591         return;
1592     }
1593
1594     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1595     lock_ReleaseWrite(&dscp->rw);
1596
1597     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1598         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1599         cm_ReleaseSCache(dscp);
1600         osi_Log1(afsd_logp, "RDR_UpdateFileEntry Not a Directory dscp=0x%p",
1601                  dscp);
1602         return;
1603     }
1604
1605     Fid.cell   = FileId.Cell;
1606     Fid.volume = FileId.Volume;
1607     Fid.vnode  = FileId.Vnode;
1608     Fid.unique = FileId.Unique;
1609     Fid.hash   = FileId.Hash;
1610
1611     code = cm_GetSCache(&Fid, &dscp->fid, &scp, userp, &req);
1612     if (code) {
1613         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1614         (*ResultCB)->ResultStatus = status;
1615         cm_ReleaseSCache(dscp);
1616         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache object FID failure code=0x%x status=0x%x",
1617                   code, status);
1618         return;
1619     }
1620
1621     lock_ObtainWrite(&scp->rw);
1622     bScpLocked = TRUE;
1623     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1624                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1625     if (code) {
1626         lock_ReleaseWrite(&scp->rw);
1627         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1628         (*ResultCB)->ResultStatus = status;
1629         (*ResultCB)->ResultBufferLength = 0;
1630         cm_ReleaseSCache(dscp);
1631         cm_ReleaseSCache(scp);
1632         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
1633                  scp, code, status);
1634         return;
1635     }
1636     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1637
1638     if (UpdateCB->ChangeTime.QuadPart) {
1639
1640         if (scp->fileType == CM_SCACHETYPE_FILE) {
1641             /* Do not set length and other attributes at the same time */
1642             if (scp->length.QuadPart != UpdateCB->AllocationSize.QuadPart) {
1643                 osi_Log2(afsd_logp, "RDR_UpdateFileEntry Length Change 0x%x -> 0x%x",
1644                           (afs_uint32)scp->length.QuadPart, (afs_uint32)UpdateCB->AllocationSize.QuadPart);
1645                 setAttr.mask |= CM_ATTRMASK_LENGTH;
1646                 setAttr.length.LowPart = UpdateCB->AllocationSize.LowPart;
1647                 setAttr.length.HighPart = UpdateCB->AllocationSize.HighPart;
1648                 lock_ReleaseWrite(&scp->rw);
1649                 bScpLocked = FALSE;
1650                 code = cm_SetAttr(scp, &setAttr, userp, &req);
1651                 if (code)
1652                     goto on_error;
1653                 setAttr.mask = 0;
1654             }
1655         }
1656
1657         if (!bScpLocked) {
1658             lock_ObtainWrite(&scp->rw);
1659             bScpLocked = TRUE;
1660         }
1661         if ((scp->unixModeBits & 0200) && (UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1662             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1663             setAttr.unixModeBits = scp->unixModeBits & ~0222;
1664         } else if (!(scp->unixModeBits & 0200) && !(UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1665             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1666             setAttr.unixModeBits = scp->unixModeBits | 0222;
1667         }
1668     }
1669
1670     if (UpdateCB->LastWriteTime.QuadPart) {
1671         ft.dwLowDateTime = UpdateCB->LastWriteTime.LowPart;
1672         ft.dwHighDateTime = UpdateCB->LastWriteTime.HighPart;
1673
1674         cm_UnixTimeFromLargeSearchTime(& clientModTime, &ft);
1675
1676         if (!bScpLocked) {
1677             lock_ObtainWrite(&scp->rw);
1678             bScpLocked = TRUE;
1679         }
1680         if (scp->clientModTime != clientModTime) {
1681             setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1682             setAttr.clientModTime = clientModTime;
1683         }
1684
1685         /* call setattr */
1686         if (setAttr.mask) {
1687             lock_ReleaseWrite(&scp->rw);
1688             bScpLocked = FALSE;
1689             code = cm_SetAttr(scp, &setAttr, userp, &req);
1690         } else
1691             code = 0;
1692     }
1693
1694   on_error:
1695     if (bScpLocked) {
1696         lock_ReleaseWrite(&scp->rw);
1697     }
1698
1699     if (code == 0) {
1700         DWORD dwRemaining = ResultBufferLength - sizeof( AFSFileUpdateResultCB) + sizeof( AFSDirEnumEntry);
1701
1702         pResultCB = (AFSFileUpdateResultCB *)(*ResultCB)->ResultData;
1703
1704         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1705
1706         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
1707                                         dscp, scp, userp, &req, NULL, NULL,
1708                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
1709                                         0, NULL, &dwRemaining);
1710         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1711         osi_Log0(afsd_logp, "RDR_UpdateFileEntry SUCCESS");
1712     } else {
1713         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1714         (*ResultCB)->ResultStatus = status;
1715         (*ResultCB)->ResultBufferLength = 0;
1716         osi_Log2(afsd_logp, "RDR_UpdateFileEntry FAILURE code=0x%x status=0x%x",
1717                   code, status);
1718     }
1719     cm_ReleaseSCache(scp);
1720     cm_ReleaseSCache(dscp);
1721
1722     return;
1723 }
1724
1725 void
1726 RDR_CleanupFileEntry( IN cm_user_t *userp,
1727                       IN AFSFileID FileId,
1728                       IN WCHAR *FileNameCounted,
1729                       IN DWORD FileNameLength,
1730                       IN AFSFileCleanupCB *CleanupCB,
1731                       IN BOOL bWow64,
1732                       IN BOOL bLastHandle,
1733                       IN BOOL bDeleteFile,
1734                       IN BOOL bUnlockFile,
1735                       IN DWORD ResultBufferLength,
1736                       IN OUT AFSCommResult **ResultCB)
1737 {
1738     AFSFileCleanupResultCB *pResultCB = NULL;
1739     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1740     cm_fid_t            Fid;
1741     cm_fid_t            parentFid;
1742     afs_uint32          code = 0;
1743     afs_uint32          flags = 0;
1744     cm_attr_t           setAttr;
1745     cm_scache_t *       scp = NULL;
1746     cm_scache_t *       dscp = NULL;
1747     cm_req_t            req;
1748     time_t              clientModTime;
1749     FILETIME            ft;
1750     DWORD               status;
1751     BOOL                bScpLocked = FALSE;
1752     BOOL                bDscpLocked = FALSE;
1753     BOOL                bFlushFile = FALSE;
1754     cm_key_t            key;
1755
1756     RDR_InitReq(&req, bWow64);
1757     memset(&setAttr, 0, sizeof(cm_attr_t));
1758
1759     osi_Log4(afsd_logp, "RDR_CleanupFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1760               CleanupCB->ParentId.Cell, CleanupCB->ParentId.Volume,
1761               CleanupCB->ParentId.Vnode, CleanupCB->ParentId.Unique);
1762     osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1763               FileId.Cell, FileId.Volume,
1764               FileId.Vnode, FileId.Unique);
1765
1766     *ResultCB = (AFSCommResult *)malloc( size);
1767     if (!(*ResultCB)) {
1768         osi_Log0(afsd_logp, "RDR_CleanupFileEntry Out of Memory");
1769         return;
1770     }
1771
1772     memset( *ResultCB,
1773             '\0',
1774             size);
1775
1776     parentFid.cell   = CleanupCB->ParentId.Cell;
1777     parentFid.volume = CleanupCB->ParentId.Volume;
1778     parentFid.vnode  = CleanupCB->ParentId.Vnode;
1779     parentFid.unique = CleanupCB->ParentId.Unique;
1780     parentFid.hash   = CleanupCB->ParentId.Hash;
1781
1782     if (parentFid.cell) {
1783         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1784         if (code) {
1785             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1786             if ( status == STATUS_INVALID_HANDLE)
1787                 status = STATUS_OBJECT_PATH_INVALID;
1788             (*ResultCB)->ResultStatus = status;
1789             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1790                      code, status);
1791             return;
1792         }
1793
1794         lock_ObtainWrite(&dscp->rw);
1795         bDscpLocked = TRUE;
1796         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1797                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1798         if (code) {
1799             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure dscp=0x%p code=0x%x",
1800                     dscp, code);
1801             if (code)
1802                 goto on_error;
1803         }
1804
1805         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1806         lock_ReleaseWrite(&dscp->rw);
1807         bDscpLocked = FALSE;
1808
1809         if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1810             (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1811             cm_ReleaseSCache(dscp);
1812             osi_Log1(afsd_logp, "RDR_CleanupFileEntry Not a Directory dscp=0x%p",
1813                      dscp);
1814             if (code)
1815                 goto on_error;
1816         }
1817     }
1818
1819     Fid.cell   = FileId.Cell;
1820     Fid.volume = FileId.Volume;
1821     Fid.vnode  = FileId.Vnode;
1822     Fid.unique = FileId.Unique;
1823     Fid.hash   = FileId.Hash;
1824
1825     code = cm_GetSCache(&Fid, dscp ? &dscp->fid : NULL, &scp, userp, &req);
1826     if (code) {
1827         osi_Log1(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache object FID failure code=0x%x",
1828                  code);
1829         goto on_error;
1830     }
1831
1832     lock_ObtainWrite(&scp->rw);
1833     bScpLocked = TRUE;
1834     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1835                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1836     if (code) {
1837         osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure scp=0x%p code=0x%x",
1838                  scp, code);
1839         goto on_error;
1840     }
1841     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1842
1843     if (bLastHandle && (scp->fileType == CM_SCACHETYPE_FILE) &&
1844         scp->redirBufCount > 0)
1845     {
1846         LARGE_INTEGER heldExtents;
1847         AFSFileExtentCB extentList[1024];
1848         DWORD extentCount = 0;
1849         cm_buf_t *srbp;
1850         time_t now;
1851
1852         time(&now);
1853         heldExtents.QuadPart = 0;
1854
1855         for ( srbp = redirq_to_cm_buf_t(scp->redirQueueT);
1856               srbp;
1857               srbp = redirq_to_cm_buf_t(osi_QPrev(&srbp->redirq)))
1858         {
1859             extentList[extentCount].Flags = 0;
1860             extentList[extentCount].Length = cm_data.blockSize;
1861             extentList[extentCount].FileOffset.QuadPart = srbp->offset.QuadPart;
1862             extentList[extentCount].CacheOffset.QuadPart = srbp->datap - RDR_extentBaseAddress;
1863             lock_ObtainWrite(&buf_globalLock);
1864             srbp->redirReleaseRequested = now;
1865             lock_ReleaseWrite(&buf_globalLock);
1866             extentCount++;
1867
1868             if (extentCount == 1024) {
1869                 lock_ReleaseWrite(&scp->rw);
1870                 code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1871                 if (code) {
1872                     if (code == CM_ERROR_RETRY) {
1873                         /*
1874                          * The redirector either is not holding the extents or cannot let them
1875                          * go because they are otherwise in use.  At the moment, do nothing.
1876                          */
1877                     } else
1878                         break;
1879                 }
1880                 extentCount = 0;
1881                 bFlushFile = TRUE;
1882                 lock_ObtainWrite(&scp->rw);
1883             }
1884         }
1885
1886         if (code == 0 && extentCount > 0) {
1887             if (bScpLocked) {
1888                 lock_ReleaseWrite(&scp->rw);
1889                 bScpLocked = FALSE;
1890             }
1891             code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1892             bFlushFile = TRUE;
1893         }
1894     }
1895
1896     /* No longer in use by redirector */
1897     if (!bScpLocked) {
1898         lock_ObtainWrite(&scp->rw);
1899         bScpLocked = TRUE;
1900     }
1901
1902     if (bLastHandle) {
1903         lock_AssertWrite(&scp->rw);
1904         scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
1905     }
1906
1907     /* If not a readonly object, flush dirty data and update metadata */
1908     if (!(scp->flags & CM_SCACHEFLAG_RO)) {
1909         if ((scp->fileType == CM_SCACHETYPE_FILE) && (bLastHandle || bFlushFile)) {
1910             /* Serialize with any outstanding AsyncStore operation */
1911             code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
1912             if (code == 0) {
1913                 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
1914
1915                 code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
1916                                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1917                 /*
1918                  * If we only have 'i' bits, then we should still be able to
1919                  * set flush the file.
1920                  */
1921                 if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
1922                     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
1923                                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1924                 }
1925                 if (code == 0) {
1926                     if (bScpLocked) {
1927                         lock_ReleaseWrite(&scp->rw);
1928                         bScpLocked = FALSE;
1929                     }
1930
1931                     code = cm_FSync(scp, userp, &req, bScpLocked);
1932                 }
1933             }
1934             if (bLastHandle && code)
1935                 goto unlock;
1936         }
1937
1938         if (CleanupCB->ChangeTime.QuadPart) {
1939
1940             if (scp->fileType == CM_SCACHETYPE_FILE) {
1941                 /* Do not set length and other attributes at the same time */
1942                 if (scp->length.QuadPart != CleanupCB->AllocationSize.QuadPart) {
1943                     osi_Log2(afsd_logp, "RDR_CleanupFileEntry Length Change 0x%x -> 0x%x",
1944                              (afs_uint32)scp->length.QuadPart, (afs_uint32)CleanupCB->AllocationSize.QuadPart);
1945                     setAttr.mask |= CM_ATTRMASK_LENGTH;
1946                     setAttr.length.LowPart = CleanupCB->AllocationSize.LowPart;
1947                     setAttr.length.HighPart = CleanupCB->AllocationSize.HighPart;
1948
1949                     if (bScpLocked) {
1950                         lock_ReleaseWrite(&scp->rw);
1951                         bScpLocked = FALSE;
1952                     }
1953                     code = cm_SetAttr(scp, &setAttr, userp, &req);
1954                     if (code)
1955                         goto unlock;
1956                     setAttr.mask = 0;
1957                 }
1958             }
1959
1960             if (!bScpLocked) {
1961                 lock_ObtainWrite(&scp->rw);
1962                 bScpLocked = TRUE;
1963             }
1964
1965             if ((scp->unixModeBits & 0200) && (CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1966                 setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1967                 setAttr.unixModeBits = scp->unixModeBits & ~0222;
1968             } else if (!(scp->unixModeBits & 0200) && !(CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1969                 setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1970                 setAttr.unixModeBits = scp->unixModeBits | 0222;
1971             }
1972         }
1973
1974         if (CleanupCB->LastWriteTime.QuadPart) {
1975             ft.dwLowDateTime = CleanupCB->LastWriteTime.LowPart;
1976             ft.dwHighDateTime = CleanupCB->LastWriteTime.HighPart;
1977
1978             cm_UnixTimeFromLargeSearchTime(&clientModTime, &ft);
1979             if (scp->clientModTime != clientModTime) {
1980                 setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1981                 setAttr.clientModTime = clientModTime;
1982             }
1983         }
1984
1985         /* call setattr */
1986         if (setAttr.mask) {
1987             if (bScpLocked) {
1988                 lock_ReleaseWrite(&scp->rw);
1989                 bScpLocked = FALSE;
1990             }
1991             code = cm_SetAttr(scp, &setAttr, userp, &req);
1992         } else
1993             code = 0;
1994     }
1995
1996   unlock:
1997     /* Now drop the lock enforcing the share access */
1998     if ( CleanupCB->FileAccess != AFS_FILE_ACCESS_NOLOCK) {
1999         unsigned int sLockType;
2000         LARGE_INTEGER LOffset, LLength;
2001
2002         if (CleanupCB->FileAccess == AFS_FILE_ACCESS_SHARED)
2003             sLockType = LOCKING_ANDX_SHARED_LOCK;
2004         else
2005             sLockType = 0;
2006
2007         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, CleanupCB->Identifier);
2008
2009         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
2010         LOffset.LowPart = SMB_FID_QLOCK_LOW;
2011         LLength.HighPart = 0;
2012         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
2013
2014         if (!bScpLocked) {
2015             lock_ObtainWrite(&scp->rw);
2016             bScpLocked = TRUE;
2017         }
2018
2019         code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
2020         if (code == 0)
2021         {
2022             code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
2023
2024             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2025
2026             if (code == CM_ERROR_RANGE_NOT_LOCKED)
2027             {
2028                 osi_Log3(afsd_logp, "RDR_CleanupFileEntry Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
2029                          CleanupCB->FileAccess, CleanupCB->ProcessId, CleanupCB->Identifier);
2030
2031             }
2032         }
2033     }
2034
2035     if (bUnlockFile || bDeleteFile) {
2036         if (!bScpLocked) {
2037             lock_ObtainWrite(&scp->rw);
2038             bScpLocked = TRUE;
2039         }
2040         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2041                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2042         if (code) {
2043             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp (2) failure scp=0x%p code=0x%x",
2044                      scp, code);
2045             goto on_error;
2046         }
2047
2048         key = cm_GenerateKey(CM_SESSION_IFS, CleanupCB->ProcessId, 0);
2049
2050         /* the scp is now locked and current */
2051         code = cm_UnlockByKey(scp, key,
2052                               bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
2053                               userp, &req);
2054
2055         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2056
2057         if (code)
2058             goto on_error;
2059     }
2060
2061   on_error:
2062     if (bDscpLocked)
2063         lock_ReleaseWrite(&dscp->rw);
2064     if (bScpLocked)
2065         lock_ReleaseWrite(&scp->rw);
2066
2067     if (code == 0 && dscp && bDeleteFile) {
2068         WCHAR FileName[260];
2069
2070         StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2071
2072         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2073             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2074         else
2075             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2076     }
2077
2078     if (code == 0) {
2079         if ( ResultBufferLength >=  sizeof( AFSFileCleanupResultCB))
2080         {
2081             (*ResultCB)->ResultBufferLength = sizeof( AFSFileCleanupResultCB);
2082             pResultCB = (AFSFileCleanupResultCB *)&(*ResultCB)->ResultData;
2083             pResultCB->ParentDataVersion.QuadPart = dscp ? dscp->dataVersion : 0;
2084         } else {
2085             (*ResultCB)->ResultBufferLength = 0;
2086         }
2087
2088         (*ResultCB)->ResultStatus = 0;
2089         osi_Log0(afsd_logp, "RDR_CleanupFileEntry SUCCESS");
2090     } else {
2091         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2092         (*ResultCB)->ResultStatus = status;
2093         osi_Log2(afsd_logp, "RDR_CleanupFileEntry FAILURE code=0x%x status=0x%x",
2094                   code, status);
2095     }
2096
2097     if (scp)
2098         cm_ReleaseSCache(scp);
2099     if (dscp)
2100         cm_ReleaseSCache(dscp);
2101
2102     return;
2103 }
2104
2105 void
2106 RDR_DeleteFileEntry( IN cm_user_t *userp,
2107                      IN AFSFileID ParentId,
2108                      IN ULONGLONG ProcessId,
2109                      IN WCHAR *FileNameCounted,
2110                      IN DWORD FileNameLength,
2111                      IN BOOL bWow64,
2112                      IN BOOL bCheckOnly,
2113                      IN DWORD ResultBufferLength,
2114                      IN OUT AFSCommResult **ResultCB)
2115 {
2116
2117     AFSFileDeleteResultCB *pResultCB = NULL;
2118     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2119     cm_fid_t            parentFid;
2120     afs_uint32          code;
2121     cm_scache_t *       dscp = NULL;
2122     cm_scache_t *       scp = NULL;
2123     afs_uint32          flags = 0;
2124     cm_attr_t           setAttr;
2125     cm_req_t            req;
2126     DWORD               status;
2127     wchar_t             FileName[260];
2128     cm_key_t            key;
2129
2130     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2131
2132     osi_Log4(afsd_logp, "RDR_DeleteFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2133               ParentId.Cell,  ParentId.Volume,
2134               ParentId.Vnode, ParentId.Unique);
2135     osi_Log2(afsd_logp, "... name=%S checkOnly=%x",
2136              osi_LogSaveStringW(afsd_logp, FileName),
2137              bCheckOnly);
2138
2139     RDR_InitReq(&req, bWow64);
2140     memset(&setAttr, 0, sizeof(cm_attr_t));
2141
2142     *ResultCB = (AFSCommResult *)malloc( size);
2143     if (!(*ResultCB)) {
2144         osi_Log0(afsd_logp, "RDR_DeleteFileEntry out of memory");
2145         return;
2146     }
2147
2148     memset( *ResultCB,
2149             '\0',
2150             size);
2151
2152     parentFid.cell   = ParentId.Cell;
2153     parentFid.volume = ParentId.Volume;
2154     parentFid.vnode  = ParentId.Vnode;
2155     parentFid.unique = ParentId.Unique;
2156     parentFid.hash   = ParentId.Hash;
2157
2158     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
2159     if (code) {
2160         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2161         if ( status == STATUS_INVALID_HANDLE)
2162             status = STATUS_OBJECT_PATH_INVALID;
2163         (*ResultCB)->ResultStatus = status;
2164         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
2165                   code, status);
2166         return;
2167     }
2168
2169     lock_ObtainWrite(&dscp->rw);
2170
2171     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
2172                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2173     if (code) {
2174         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2175         (*ResultCB)->ResultStatus = status;
2176         (*ResultCB)->ResultBufferLength = 0;
2177         lock_ReleaseWrite(&dscp->rw);
2178         cm_ReleaseSCache(dscp);
2179         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
2180                  dscp, code, status);
2181         return;
2182     }
2183
2184     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2185     lock_ReleaseWrite(&dscp->rw);
2186
2187     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2188         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2189         cm_ReleaseSCache(dscp);
2190         osi_Log1(afsd_logp, "RDR_DeleteFileEntry Not a Directory dscp=0x%p",
2191                  dscp);
2192         return;
2193     }
2194
2195     code = cm_Lookup(dscp, FileName, 0, userp, &req, &scp);
2196     if (code) {
2197         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2198         (*ResultCB)->ResultStatus = status;
2199         (*ResultCB)->ResultBufferLength = 0;
2200         cm_ReleaseSCache(dscp);
2201         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_Lookup failure code=0x%x status=0x%x",
2202                  code, status);
2203         return;
2204     }
2205
2206     lock_ObtainWrite(&scp->rw);
2207     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_DELETE,
2208                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2209     if (code) {
2210         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2211         (*ResultCB)->ResultStatus = status;
2212         (*ResultCB)->ResultBufferLength = 0;
2213         lock_ReleaseWrite(&scp->rw);
2214         cm_ReleaseSCache(scp);
2215         cm_ReleaseSCache(dscp);
2216         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
2217                  scp, code, status);
2218         return;
2219     }
2220
2221     if (!bCheckOnly) {
2222         /* Drop all locks since the file is being deleted */
2223         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2224                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2225         if (code) {
2226             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2227             (*ResultCB)->ResultStatus = status;
2228             (*ResultCB)->ResultBufferLength = 0;
2229             lock_ReleaseWrite(&scp->rw);
2230             cm_ReleaseSCache(scp);
2231             cm_ReleaseSCache(dscp);
2232             osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp Lock failure scp=0x%p code=0x%x status=0x%x",
2233                      scp, code, status);
2234         }
2235
2236         /* the scp is now locked and current */
2237         key = cm_GenerateKey(CM_SESSION_IFS, ProcessId, 0);
2238
2239         code = cm_UnlockByKey(scp, key,
2240                               CM_UNLOCK_FLAG_BY_FID,
2241                               userp, &req);
2242
2243         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2244         lock_ReleaseWrite(&scp->rw);
2245
2246         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2247             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2248         else
2249             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2250     } else {
2251         lock_ReleaseWrite(&scp->rw);
2252     }
2253
2254     if (code == 0) {
2255         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
2256
2257         (*ResultCB)->ResultBufferLength = sizeof( AFSFileDeleteResultCB);
2258
2259         pResultCB = (AFSFileDeleteResultCB *)(*ResultCB)->ResultData;
2260
2261         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
2262         osi_Log0(afsd_logp, "RDR_DeleteFileEntry SUCCESS");
2263     } else {
2264         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2265         (*ResultCB)->ResultStatus = status;
2266         (*ResultCB)->ResultBufferLength = 0;
2267         osi_Log2(afsd_logp, "RDR_DeleteFileEntry FAILURE code=0x%x status=0x%x",
2268                   code, status);
2269     }
2270
2271     cm_ReleaseSCache(dscp);
2272     cm_ReleaseSCache(scp);
2273
2274     return;
2275 }
2276
2277 void
2278 RDR_RenameFileEntry( IN cm_user_t *userp,
2279                      IN WCHAR    *SourceFileNameCounted,
2280                      IN DWORD     SourceFileNameLength,
2281                      IN AFSFileID SourceFileId,
2282                      IN AFSFileRenameCB *pRenameCB,
2283                      IN BOOL bWow64,
2284                      IN DWORD ResultBufferLength,
2285                      IN OUT AFSCommResult **ResultCB)
2286 {
2287
2288     AFSFileRenameResultCB *pResultCB = NULL;
2289     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2290     AFSFileID              SourceParentId   = pRenameCB->SourceParentId;
2291     AFSFileID              TargetParentId   = pRenameCB->TargetParentId;
2292     WCHAR *                TargetFileNameCounted = pRenameCB->TargetName;
2293     DWORD                  TargetFileNameLength = pRenameCB->TargetNameLength;
2294     cm_fid_t               SourceParentFid;
2295     cm_fid_t               TargetParentFid;
2296     cm_fid_t               SourceFid;
2297     cm_fid_t               OrigTargetFid = {0,0,0,0,0};
2298     cm_fid_t               TargetFid;
2299     cm_scache_t *          oldDscp;
2300     cm_scache_t *          newDscp;
2301     cm_dirOp_t dirop;
2302     wchar_t                shortName[13];
2303     wchar_t                SourceFileName[260];
2304     wchar_t                TargetFileName[260];
2305     cm_dirFid_t            dfid;
2306     cm_req_t               req;
2307     afs_uint32             code;
2308     DWORD                  status;
2309
2310     RDR_InitReq(&req, bWow64);
2311
2312     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
2313     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
2314
2315     osi_Log4(afsd_logp, "RDR_RenameFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2316               SourceParentId.Cell,  SourceParentId.Volume,
2317               SourceParentId.Vnode, SourceParentId.Unique);
2318     osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
2319     osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2320               TargetParentId.Cell,  TargetParentId.Volume,
2321               TargetParentId.Vnode, TargetParentId.Unique);
2322     osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
2323
2324     *ResultCB = (AFSCommResult *)malloc( size);
2325     if (!(*ResultCB))
2326         return;
2327
2328     memset( *ResultCB,
2329             '\0',
2330             size);
2331
2332     pResultCB = (AFSFileRenameResultCB *)(*ResultCB)->ResultData;
2333
2334     if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
2335     {
2336         osi_Log2(afsd_logp, "RDR_RenameFileEntry Invalid Name Length: src %u target %u",
2337                  SourceFileNameLength, TargetFileNameLength);
2338         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
2339         return;
2340     }
2341
2342     SourceParentFid.cell   = SourceParentId.Cell;
2343     SourceParentFid.volume = SourceParentId.Volume;
2344     SourceParentFid.vnode  = SourceParentId.Vnode;
2345     SourceParentFid.unique = SourceParentId.Unique;
2346     SourceParentFid.hash   = SourceParentId.Hash;
2347
2348     TargetParentFid.cell   = TargetParentId.Cell;
2349     TargetParentFid.volume = TargetParentId.Volume;
2350     TargetParentFid.vnode  = TargetParentId.Vnode;
2351     TargetParentFid.unique = TargetParentId.Unique;
2352     TargetParentFid.hash   = TargetParentId.Hash;
2353
2354     code = cm_GetSCache(&SourceParentFid, NULL, &oldDscp, userp, &req);
2355     if (code) {
2356         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache source parent failed code 0x%x", code);
2357         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2358         if ( status == STATUS_INVALID_HANDLE)
2359             status = STATUS_OBJECT_PATH_INVALID;
2360         (*ResultCB)->ResultStatus = status;
2361         return;
2362     }
2363
2364     lock_ObtainWrite(&oldDscp->rw);
2365     code = cm_SyncOp(oldDscp, NULL, userp, &req, 0,
2366                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2367     if (code) {
2368         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp oldDscp 0x%p failed code 0x%x", oldDscp, code);
2369         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2370         if ( status == STATUS_INVALID_HANDLE)
2371             status = STATUS_OBJECT_PATH_INVALID;
2372         (*ResultCB)->ResultStatus = status;
2373         lock_ReleaseWrite(&oldDscp->rw);
2374         cm_ReleaseSCache(oldDscp);
2375         return;
2376     }
2377
2378     cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2379     lock_ReleaseWrite(&oldDscp->rw);
2380
2381
2382     if (oldDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2383         osi_Log1(afsd_logp, "RDR_RenameFileEntry oldDscp 0x%p not a directory", oldDscp);
2384         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2385         cm_ReleaseSCache(oldDscp);
2386         return;
2387     }
2388
2389     code = cm_GetSCache(&TargetParentFid, NULL, &newDscp, userp, &req);
2390     if (code) {
2391         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target parent failed code 0x%x", code);
2392         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2393         (*ResultCB)->ResultStatus = status;
2394         cm_ReleaseSCache(oldDscp);
2395         return;
2396     }
2397
2398     lock_ObtainWrite(&newDscp->rw);
2399     code = cm_SyncOp(newDscp, NULL, userp, &req, 0,
2400                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2401     if (code) {
2402         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp newDscp 0x%p failed code 0x%x", newDscp, code);
2403         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2404         (*ResultCB)->ResultStatus = status;
2405         lock_ReleaseWrite(&newDscp->rw);
2406         cm_ReleaseSCache(oldDscp);
2407         cm_ReleaseSCache(newDscp);
2408         return;
2409     }
2410
2411     cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2412     lock_ReleaseWrite(&newDscp->rw);
2413
2414
2415     if (newDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2416         osi_Log1(afsd_logp, "RDR_RenameFileEntry newDscp 0x%p not a directory", newDscp);
2417         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2418         cm_ReleaseSCache(oldDscp);
2419         cm_ReleaseSCache(newDscp);
2420         return;
2421     }
2422
2423     /* Obtain the original FID just for debugging purposes */
2424     code = cm_BeginDirOp( oldDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2425     if (code == 0) {
2426         code = cm_BPlusDirLookup(&dirop, SourceFileName, &SourceFid);
2427         code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
2428         cm_EndDirOp(&dirop);
2429     }
2430
2431     code = cm_Rename( oldDscp, NULL, SourceFileName,
2432                       newDscp, TargetFileName, userp, &req);
2433     if (code == 0) {
2434         cm_scache_t *scp = 0;
2435         DWORD dwRemaining;
2436
2437         (*ResultCB)->ResultBufferLength = ResultBufferLength;
2438         dwRemaining = ResultBufferLength - sizeof( AFSFileRenameResultCB) + sizeof( AFSDirEnumEntry);
2439         (*ResultCB)->ResultStatus = 0;
2440
2441         pResultCB->SourceParentDataVersion.QuadPart = oldDscp->dataVersion;
2442         pResultCB->TargetParentDataVersion.QuadPart = newDscp->dataVersion;
2443
2444         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p SUCCESS",
2445                  oldDscp, newDscp);
2446
2447         code = cm_BeginDirOp( newDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2448         if (code == 0) {
2449             code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
2450             cm_EndDirOp(&dirop);
2451         }
2452
2453         if (code != 0) {
2454             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_BPlusDirLookup failed code 0x%x",
2455                      code);
2456             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
2457             cm_ReleaseSCache(oldDscp);
2458             cm_ReleaseSCache(newDscp);
2459             return;
2460         }
2461
2462         osi_Log4(afsd_logp, "RDR_RenameFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2463                   TargetFid.cell,  TargetFid.volume,
2464                   TargetFid.vnode, TargetFid.unique);
2465
2466         code = cm_GetSCache(&TargetFid, &newDscp->fid, &scp, userp, &req);
2467         if (code) {
2468             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target failed code 0x%x", code);
2469             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2470             (*ResultCB)->ResultStatus = status;
2471             cm_ReleaseSCache(oldDscp);
2472             cm_ReleaseSCache(newDscp);
2473             return;
2474         }
2475
2476         /* Make sure the source vnode is current */
2477         lock_ObtainWrite(&scp->rw);
2478         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2479                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2480         if (code) {
2481             osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp scp 0x%p failed code 0x%x", scp, code);
2482             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2483             (*ResultCB)->ResultStatus = status;
2484             lock_ReleaseWrite(&scp->rw);
2485             cm_ReleaseSCache(oldDscp);
2486             cm_ReleaseSCache(newDscp);
2487             cm_ReleaseSCache(scp);
2488             return;
2489         }
2490
2491         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2492         lock_ReleaseWrite(&scp->rw);
2493
2494         if (cm_shortNames) {
2495             dfid.vnode = htonl(scp->fid.vnode);
2496             dfid.unique = htonl(scp->fid.unique);
2497
2498             if (!cm_Is8Dot3(TargetFileName))
2499                 cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
2500             else
2501                 shortName[0] = '\0';
2502         }
2503
2504         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
2505                                  newDscp, scp, userp, &req, TargetFileName, shortName,
2506                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
2507                                  0, NULL, &dwRemaining);
2508         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
2509         cm_ReleaseSCache(scp);
2510
2511         osi_Log0(afsd_logp, "RDR_RenameFileEntry SUCCESS");
2512     } else {
2513         osi_Log3(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p failed code 0x%x",
2514                  oldDscp, newDscp, code);
2515         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2516         (*ResultCB)->ResultStatus = status;
2517         (*ResultCB)->ResultBufferLength = 0;
2518     }
2519
2520     cm_ReleaseSCache(oldDscp);
2521     cm_ReleaseSCache(newDscp);
2522     return;
2523 }
2524
2525 /*
2526  * AFS does not support cross-directory hard links but RDR_HardLinkFileEntry
2527  * is written as if AFS does.  The check for cross-directory links is
2528  * implemented in cm_Link().
2529  *
2530  * Windows supports optional ReplaceIfExists functionality.  The AFS file
2531  * server does not.  If the target name already exists and bReplaceIfExists
2532  * is true, check to see if the user has insert permission before calling
2533  * cm_Unlink() on the existing object.  If the user does not have insert
2534  * permission return STATUS_ACCESS_DENIED.
2535  */
2536
2537 void
2538 RDR_HardLinkFileEntry( IN cm_user_t *userp,
2539                        IN WCHAR    *SourceFileNameCounted,
2540                        IN DWORD     SourceFileNameLength,
2541                        IN AFSFileID SourceFileId,
2542                        IN AFSFileHardLinkCB *pHardLinkCB,
2543                        IN BOOL bWow64,
2544                        IN DWORD ResultBufferLength,
2545                        IN OUT AFSCommResult **ResultCB)
2546 {
2547
2548     AFSFileHardLinkResultCB *pResultCB = NULL;
2549     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2550     AFSFileID              SourceParentId   = pHardLinkCB->SourceParentId;
2551     AFSFileID              TargetParentId   = pHardLinkCB->TargetParentId;
2552     WCHAR *                TargetFileNameCounted = pHardLinkCB->TargetName;
2553     DWORD                  TargetFileNameLength = pHardLinkCB->TargetNameLength;
2554     cm_fid_t               SourceParentFid;
2555     cm_fid_t               TargetParentFid;
2556     cm_fid_t               SourceFid;
2557     cm_fid_t               OrigTargetFid = {0,0,0,0,0};
2558     cm_scache_t *          srcDscp = NULL;
2559     cm_scache_t *          targetDscp = NULL;
2560     cm_scache_t *          srcScp = NULL;
2561     cm_dirOp_t             dirop;
2562     wchar_t                shortName[13];
2563     wchar_t                SourceFileName[260];
2564     wchar_t                TargetFileName[260];
2565     cm_dirFid_t            dfid;
2566     cm_req_t               req;
2567     afs_uint32             code;
2568     DWORD                  status;
2569
2570     RDR_InitReq(&req, bWow64);
2571
2572     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
2573     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
2574
2575     osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2576               SourceParentId.Cell,  SourceParentId.Volume,
2577               SourceParentId.Vnode, SourceParentId.Unique);
2578     osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
2579     osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2580               TargetParentId.Cell,  TargetParentId.Volume,
2581               TargetParentId.Vnode, TargetParentId.Unique);
2582     osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
2583
2584     *ResultCB = (AFSCommResult *)malloc( size);
2585     if (!(*ResultCB))
2586         return;
2587
2588     memset( *ResultCB,
2589             '\0',
2590             size);
2591
2592     pResultCB = (AFSFileHardLinkResultCB *)(*ResultCB)->ResultData;
2593
2594     if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
2595     {
2596         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry Invalid Name Length: src %u target %u",
2597                  SourceFileNameLength, TargetFileNameLength);
2598         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
2599         return;
2600     }
2601
2602     SourceFid.cell   = SourceFileId.Cell;
2603     SourceFid.volume = SourceFileId.Volume;
2604     SourceFid.vnode  = SourceFileId.Vnode;
2605     SourceFid.unique = SourceFileId.Unique;
2606     SourceFid.hash   = SourceFileId.Hash;
2607
2608     SourceParentFid.cell   = SourceParentId.Cell;
2609     SourceParentFid.volume = SourceParentId.Volume;
2610     SourceParentFid.vnode  = SourceParentId.Vnode;
2611     SourceParentFid.unique = SourceParentId.Unique;
2612     SourceParentFid.hash   = SourceParentId.Hash;
2613
2614     TargetParentFid.cell   = TargetParentId.Cell;
2615     TargetParentFid.volume = TargetParentId.Volume;
2616     TargetParentFid.vnode  = TargetParentId.Vnode;
2617     TargetParentFid.unique = TargetParentId.Unique;
2618     TargetParentFid.hash   = TargetParentId.Hash;
2619
2620     code = cm_GetSCache(&SourceFid, NULL, &srcScp, userp, &req);
2621     if (code) {
2622         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache source failed code 0x%x", code);
2623         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2624         (*ResultCB)->ResultStatus = status;
2625         return;
2626     }
2627
2628     code = cm_GetSCache(&TargetParentFid, NULL, &targetDscp, userp, &req);
2629     if (code) {
2630         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target parent failed code 0x%x", code);
2631         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2632         (*ResultCB)->ResultStatus = status;
2633         cm_ReleaseSCache(srcScp);
2634         return;
2635     }
2636
2637     lock_ObtainWrite(&targetDscp->rw);
2638     code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT,
2639                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2640     if (code) {
2641         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp targetDscp 0x%p failed code 0x%x", targetDscp, code);
2642         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2643         (*ResultCB)->ResultStatus = status;
2644         lock_ReleaseWrite(&targetDscp->rw);
2645         cm_ReleaseSCache(srcScp);
2646         cm_ReleaseSCache(targetDscp);
2647         return;
2648     }
2649
2650     cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2651     lock_ReleaseWrite(&targetDscp->rw);
2652
2653     if (targetDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2654         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry targetDscp 0x%p not a directory", targetDscp);
2655         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2656         cm_ReleaseSCache(srcScp);
2657         cm_ReleaseSCache(targetDscp);
2658         return;
2659     }
2660
2661     if ( cm_FidCmp(&SourceParentFid, &TargetParentFid) ) {
2662         code = cm_GetSCache(&SourceParentFid, NULL, &srcDscp, userp, &req);
2663         if (code) {
2664             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache source parent failed code 0x%x", code);
2665             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2666             if ( status == STATUS_INVALID_HANDLE)
2667                 status = STATUS_OBJECT_PATH_INVALID;
2668             (*ResultCB)->ResultStatus = status;
2669             cm_ReleaseSCache(srcScp);
2670             cm_ReleaseSCache(targetDscp);
2671             return;
2672         }
2673
2674         lock_ObtainWrite(&srcDscp->rw);
2675         code = cm_SyncOp(srcDscp, NULL, userp, &req, 0,
2676                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2677         if (code) {
2678             osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp srcDscp 0x%p failed code 0x%x", srcDscp, code);
2679             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2680             if ( status == STATUS_INVALID_HANDLE)
2681                 status = STATUS_OBJECT_PATH_INVALID;
2682             (*ResultCB)->ResultStatus = status;
2683             lock_ReleaseWrite(&srcDscp->rw);
2684             if (srcDscp != targetDscp)
2685                 cm_ReleaseSCache(srcDscp);
2686             cm_ReleaseSCache(targetDscp);
2687             cm_ReleaseSCache(srcScp);
2688             return;
2689         }
2690
2691         cm_SyncOpDone(srcDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2692         lock_ReleaseWrite(&srcDscp->rw);
2693
2694         if (srcDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2695             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry srcDscp 0x%p not a directory", srcDscp);
2696             (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2697             if (srcDscp != targetDscp)
2698                 cm_ReleaseSCache(srcDscp);
2699             cm_ReleaseSCache(targetDscp);
2700             cm_ReleaseSCache(srcScp);
2701             return;
2702         }
2703     } else {
2704         srcDscp = targetDscp;
2705     }
2706
2707     /* Obtain the target FID if it exists */
2708     code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2709     if (code == 0) {
2710         code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
2711         cm_EndDirOp(&dirop);
2712     }
2713
2714     if (OrigTargetFid.vnode) {
2715
2716         /* An object exists with the target name */
2717         if (!pHardLinkCB->bReplaceIfExists) {
2718             osi_Log0(afsd_logp, "RDR_HardLinkFileEntry target name collision and !ReplaceIfExists");
2719             (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_COLLISION;
2720             if (srcDscp != targetDscp)
2721                 cm_ReleaseSCache(srcDscp);
2722             cm_ReleaseSCache(targetDscp);
2723             cm_ReleaseSCache(srcScp);
2724             return;
2725         }
2726
2727         lock_ObtainWrite(&targetDscp->rw);
2728         code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT | PRSFS_DELETE,
2729                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2730         if (code) {
2731             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2732             (*ResultCB)->ResultStatus = status;
2733             lock_ReleaseWrite(&srcDscp->rw);
2734             if (srcDscp != targetDscp)
2735                 cm_ReleaseSCache(srcDscp);
2736             cm_ReleaseSCache(targetDscp);
2737             cm_ReleaseSCache(srcScp);
2738             return;
2739         }
2740         cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2741         lock_ReleaseWrite(&targetDscp->rw);
2742
2743         code = cm_Unlink(targetDscp, NULL, TargetFileName, userp, &req);
2744         if (code) {
2745             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_Unlink code 0x%x", code);
2746             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2747             (*ResultCB)->ResultStatus = status;
2748             lock_ReleaseWrite(&srcDscp->rw);
2749             if (srcDscp != targetDscp)
2750                 cm_ReleaseSCache(srcDscp);
2751             cm_ReleaseSCache(targetDscp);
2752             cm_ReleaseSCache(srcScp);
2753             return;
2754         }
2755     }
2756
2757     code = cm_Link( targetDscp, TargetFileName, srcScp, 0, userp, &req);
2758     if (code == 0) {
2759         cm_fid_t TargetFid;
2760         cm_scache_t *targetScp = 0;
2761         DWORD dwRemaining;
2762
2763         (*ResultCB)->ResultBufferLength = ResultBufferLength;
2764         dwRemaining = ResultBufferLength - sizeof( AFSFileHardLinkResultCB) + sizeof( AFSDirEnumEntry);
2765         (*ResultCB)->ResultStatus = 0;
2766
2767         pResultCB->SourceParentDataVersion.QuadPart = srcDscp->dataVersion;
2768         pResultCB->TargetParentDataVersion.QuadPart = targetDscp->dataVersion;
2769
2770         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p SUCCESS",
2771                  srcDscp, targetDscp);
2772
2773         code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2774         if (code == 0) {
2775             code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
2776             cm_EndDirOp(&dirop);
2777         }
2778
2779         if (code != 0) {
2780             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_BPlusDirLookup failed code 0x%x",
2781                      code);
2782             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
2783             if (srcDscp != targetDscp)
2784                 cm_ReleaseSCache(srcDscp);
2785             cm_ReleaseSCache(srcScp);
2786             cm_ReleaseSCache(targetDscp);
2787             return;
2788         }
2789
2790         osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2791                   TargetFid.cell,  TargetFid.volume,
2792                   TargetFid.vnode, TargetFid.unique);
2793
2794         code = cm_GetSCache(&TargetFid, &targetDscp->fid, &targetScp, userp, &req);
2795         if (code) {
2796             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target failed code 0x%x", code);
2797             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2798             (*ResultCB)->ResultStatus = status;
2799             if (srcDscp != targetDscp)
2800                 cm_ReleaseSCache(srcDscp);
2801             cm_ReleaseSCache(srcScp);
2802             cm_ReleaseSCache(targetDscp);
2803             return;
2804         }
2805
2806         /* Make sure the source vnode is current */
2807         lock_ObtainWrite(&targetScp->rw);
2808         code = cm_SyncOp(targetScp, NULL, userp, &req, 0,
2809                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2810         if (code) {
2811             osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp scp 0x%p failed code 0x%x",
2812                      targetScp, code);
2813             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2814             (*ResultCB)->ResultStatus = status;
2815             lock_ReleaseWrite(&targetScp->rw);
2816             cm_ReleaseSCache(targetScp);
2817             if (srcDscp != targetDscp)
2818                 cm_ReleaseSCache(srcDscp);
2819             cm_ReleaseSCache(srcScp);
2820             cm_ReleaseSCache(targetDscp);
2821             return;
2822         }
2823
2824         cm_SyncOpDone(targetScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2825         lock_ReleaseWrite(&targetScp->rw);
2826
2827         if (cm_shortNames) {
2828             dfid.vnode = htonl(targetScp->fid.vnode);
2829             dfid.unique = htonl(targetScp->fid.unique);
2830
2831             if (!cm_Is8Dot3(TargetFileName))
2832                 cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
2833             else
2834                 shortName[0] = '\0';
2835         }
2836
2837         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
2838                                  targetDscp, targetScp, userp, &req, TargetFileName, shortName,
2839                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
2840                                  0, NULL, &dwRemaining);
2841         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
2842         cm_ReleaseSCache(targetScp);
2843
2844         osi_Log0(afsd_logp, "RDR_HardLinkFileEntry SUCCESS");
2845     } else {
2846         osi_Log3(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p failed code 0x%x",
2847                  srcDscp, targetDscp, code);
2848         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2849         (*ResultCB)->ResultStatus = status;
2850         (*ResultCB)->ResultBufferLength = 0;
2851     }
2852
2853     cm_ReleaseSCache(srcScp);
2854     if (srcDscp != targetDscp)
2855         cm_ReleaseSCache(srcDscp);
2856     cm_ReleaseSCache(targetDscp);
2857     return;
2858 }
2859
2860
2861 void
2862 RDR_CreateSymlinkEntry( IN cm_user_t *userp,
2863                         IN AFSFileID FileId,
2864                         IN WCHAR *FileNameCounted,
2865                         IN DWORD FileNameLength,
2866                         IN AFSCreateSymlinkCB *SymlinkCB,
2867                         IN BOOL bWow64,
2868                         IN DWORD ResultBufferLength,
2869                         IN OUT AFSCommResult **ResultCB)
2870 {
2871     AFSCreateSymlinkResultCB *pResultCB = NULL;
2872     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2873     cm_fid_t            parentFid;
2874     cm_fid_t            Fid;
2875     afs_uint32          code;
2876     cm_scache_t *       dscp = NULL;
2877     afs_uint32          flags = 0;
2878     cm_attr_t           setAttr;
2879     cm_scache_t *       scp = NULL;
2880     cm_req_t            req;
2881     DWORD               status;
2882     wchar_t             FileName[260];
2883     char               *TargetPath = NULL;
2884
2885     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2886     TargetPath = cm_Utf16ToUtf8Alloc( SymlinkCB->TargetName,  SymlinkCB->TargetNameLength / sizeof(WCHAR), NULL);
2887
2888     osi_Log4( afsd_logp, "RDR_CreateSymlinkEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2889               SymlinkCB->ParentId.Cell, SymlinkCB->ParentId.Volume,
2890               SymlinkCB->ParentId.Vnode, SymlinkCB->ParentId.Unique);
2891     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
2892
2893     RDR_InitReq(&req, bWow64);
2894     memset(&setAttr, 0, sizeof(cm_attr_t));
2895
2896     *ResultCB = (AFSCommResult *)malloc(size);
2897     if (!(*ResultCB)) {
2898         osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry out of memory");
2899         free(TargetPath);
2900         return;
2901     }
2902
2903     memset( *ResultCB,
2904             '\0',
2905             size);
2906
2907     parentFid.cell   = SymlinkCB->ParentId.Cell;
2908     parentFid.volume = SymlinkCB->ParentId.Volume;
2909     parentFid.vnode  = SymlinkCB->ParentId.Vnode;
2910     parentFid.unique = SymlinkCB->ParentId.Unique;
2911     parentFid.hash   = SymlinkCB->ParentId.Hash;
2912
2913     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
2914     if (code) {
2915         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2916         (*ResultCB)->ResultStatus = status;
2917         if ( status == STATUS_INVALID_HANDLE)
2918             status = STATUS_OBJECT_PATH_INVALID;
2919         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
2920                   code, status);
2921         free(TargetPath);
2922         return;
2923     }
2924
2925     lock_ObtainWrite(&dscp->rw);
2926     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
2927                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2928     if (code) {
2929         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2930         (*ResultCB)->ResultStatus = status;
2931         lock_ReleaseWrite(&dscp->rw);
2932         cm_ReleaseSCache(dscp);
2933         osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
2934                  dscp, code, status);
2935         free(TargetPath);
2936         return;
2937     }
2938
2939     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2940     lock_ReleaseWrite(&dscp->rw);
2941
2942     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2943         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2944         cm_ReleaseSCache(dscp);
2945         osi_Log1(afsd_logp, "RDR_CreateSymlinkEntry Not a Directory dscp=0x%p",
2946                  dscp);
2947         free(TargetPath);
2948         return;
2949     }
2950
2951     Fid.cell   = FileId.Cell;
2952     Fid.volume = FileId.Volume;
2953     Fid.vnode  = FileId.Vnode;
2954     Fid.unique = FileId.Unique;
2955     Fid.hash   = FileId.Hash;
2956
2957     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
2958     if (code) {
2959         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2960         (*ResultCB)->ResultStatus = status;
2961         if ( status == STATUS_INVALID_HANDLE)
2962             status = STATUS_OBJECT_PATH_INVALID;
2963         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry cm_GetSCache FID failure code=0x%x status=0x%x",
2964                   code, status);
2965         free(TargetPath);
2966         return;
2967     }
2968
2969     lock_ObtainWrite(&scp->rw);
2970     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2971                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2972     if (code) {
2973         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2974         (*ResultCB)->ResultStatus = status;
2975         lock_ReleaseWrite(&scp->rw);
2976         cm_ReleaseSCache(scp);
2977         osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) scp=0x%p code=0x%x status=0x%x",
2978                  scp, code, status);
2979         free(TargetPath);
2980         return;
2981     }
2982
2983     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2984     lock_ReleaseWrite(&scp->rw);
2985
2986     /* Remove the temporary object */
2987     if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2988         code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2989     else
2990         code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2991     cm_ReleaseSCache(scp);
2992     scp = NULL;
2993     if (code && code != CM_ERROR_NOSUCHFILE) {
2994         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2995         (*ResultCB)->ResultStatus = status;
2996         cm_ReleaseSCache(dscp);
2997         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry Unable to delete file dscp=0x%p code=0x%x",
2998                  dscp, code);
2999         free(TargetPath);
3000         return;
3001     }
3002
3003     /*
3004      * The target path is going to be provided by the redirector in one of the following forms:
3005      *
3006      * 1. Relative path.
3007      * 2. Absolute path prefaced as \??\UNC\<server>\<share>\<path>
3008      * 3. Absolute path prefaced as \??\<drive-letter>:\<path>
3009      *
3010      * Relative paths can be used with just slash conversion.  Absolute paths must be converted.
3011      * UNC paths with a server name that matches cm_NetbiosName then the path is an AFS path and
3012      * it must be converted to /<server>/<share>/<path>.  Other UNC paths must be converted to
3013      * msdfs:\\<server>\<share>\<path>.  Local disk paths should be converted to
3014      * msdfs:<drive-letter>:<path>.
3015      */
3016
3017     if ( TargetPath[0] == '\\' ) {
3018         size_t nbNameLen = strlen(cm_NetbiosName);
3019         size_t len;
3020         char  *s;
3021
3022         if ( strncmp(TargetPath, "\\??\\UNC\\", 8) == 0) {
3023
3024             if (strncmp(&TargetPath[8], cm_NetbiosName, nbNameLen) == 0 &&
3025                 TargetPath[8 + nbNameLen] == '\\')
3026             {
3027                 /* AFS path */
3028                 s = strdup(&TargetPath[8 + nbNameLen]);
3029                 free(TargetPath);
3030                 TargetPath = s;
3031                 for (; *s; s++) {
3032                     if (*s == '\\')
3033                         *s = '/';
3034                 }
3035             } else {
3036                 /*
3037                  * non-AFS UNC path (msdfs:\\server\share\path)
3038                  * strlen("msdfs:\\") == 7 + 1 for the NUL
3039                  */
3040                 len = 8 + strlen(&TargetPath[7]);
3041                 s = malloc(8 + strlen(&TargetPath[7]));
3042                 StringCbCopy(s, len, "msdfs:\\");
3043                 StringCbCat(s, len, &TargetPath[7]);
3044                 free(TargetPath);
3045                 TargetPath = s;
3046             }
3047         } else {
3048             /* non-UNC path (msdfs:<drive>:\<path> */
3049             s = strdup(&TargetPath[4]);
3050             free(TargetPath);
3051             TargetPath = s;
3052         }
3053
3054     } else {
3055         /* relative paths require slash conversion */
3056         char *s = TargetPath;
3057         for (; *s; s++) {
3058             if (*s == '\\')
3059                 *s = '/';
3060         }
3061     }
3062
3063     /* Use current time */
3064     setAttr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
3065     setAttr.unixModeBits = 0755;
3066     setAttr.clientModTime = time(NULL);
3067
3068     code = cm_SymLink(dscp, FileName, TargetPath, flags, &setAttr, userp, &req, &scp);
3069     free(TargetPath);
3070
3071     if (code == 0) {
3072         wchar_t shortName[13]=L"";
3073         cm_dirFid_t dfid;
3074         DWORD dwRemaining;
3075
3076         if (dscp->flags & CM_SCACHEFLAG_ANYWATCH) {
3077             smb_NotifyChange(FILE_ACTION_ADDED,
3078                              FILE_NOTIFY_CHANGE_DIR_NAME,
3079                              dscp, FileName, NULL, TRUE);
3080         }
3081
3082         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
3083
3084         (*ResultCB)->ResultBufferLength = sizeof( AFSCreateSymlinkResultCB);
3085
3086         pResultCB = (AFSCreateSymlinkResultCB *)(*ResultCB)->ResultData;
3087
3088         dwRemaining = ResultBufferLength - sizeof( AFSCreateSymlinkResultCB) + sizeof( AFSDirEnumEntry);
3089
3090         lock_ObtainWrite(&dscp->rw);
3091         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
3092                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3093         if (code) {
3094             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3095             (*ResultCB)->ResultStatus = status;
3096             lock_ReleaseWrite(&dscp->rw);
3097             cm_ReleaseSCache(dscp);
3098             cm_ReleaseSCache(scp);
3099             osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
3100                       dscp, code, status);
3101             return;
3102         }
3103
3104         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
3105
3106         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3107         lock_ReleaseWrite(&dscp->rw);
3108
3109         if (cm_shortNames) {
3110             dfid.vnode = htonl(scp->fid.vnode);
3111             dfid.unique = htonl(scp->fid.unique);
3112
3113             if (!cm_Is8Dot3(FileName))
3114                 cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
3115             else
3116                 shortName[0] = '\0';
3117         }
3118
3119         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
3120                                         dscp, scp, userp, &req, FileName, shortName,
3121                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
3122                                         0, NULL, &dwRemaining);
3123         cm_ReleaseSCache(scp);
3124         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
3125         osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry SUCCESS");
3126     } else {
3127         (*ResultCB)->ResultStatus = STATUS_FILE_DELETED;
3128         (*ResultCB)->ResultBufferLength = 0;
3129         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry FAILURE code=0x%x status=0x%x",
3130                   code, STATUS_FILE_DELETED);
3131     }
3132
3133     cm_ReleaseSCache(dscp);
3134
3135     return;
3136 }
3137
3138
3139 void
3140 RDR_FlushFileEntry( IN cm_user_t *userp,
3141                     IN AFSFileID FileId,
3142                     IN BOOL bWow64,
3143                     IN DWORD ResultBufferLength,
3144                     IN OUT AFSCommResult **ResultCB)
3145 {
3146     cm_scache_t *scp = NULL;
3147     cm_fid_t    Fid;
3148     afs_uint32  code;
3149     cm_req_t    req;
3150     DWORD       status;
3151 #ifdef ODS_DEBUG
3152     char        dbgstr[1024];
3153 #endif
3154
3155     RDR_InitReq(&req, bWow64);
3156
3157     osi_Log4(afsd_logp, "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x",
3158               FileId.Cell, FileId.Volume,
3159               FileId.Vnode, FileId.Unique);
3160 #ifdef ODS_DEBUG
3161     snprintf( dbgstr, 1024,
3162               "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x\n",
3163               FileId.Cell, FileId.Volume,
3164               FileId.Vnode, FileId.Unique);
3165     OutputDebugStringA( dbgstr);
3166 #endif
3167
3168     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
3169     if (!(*ResultCB)) {
3170         osi_Log0(afsd_logp, "RDR_FlushFileEntry out of memory");
3171         return;
3172     }
3173
3174     memset( *ResultCB,
3175             '\0',
3176             sizeof( AFSCommResult));
3177
3178     /* Process the release */
3179     Fid.cell = FileId.Cell;
3180     Fid.volume = FileId.Volume;
3181     Fid.vnode = FileId.Vnode;
3182     Fid.unique = FileId.Unique;
3183     Fid.hash = FileId.Hash;
3184
3185     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3186     if (code) {
3187         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3188         (*ResultCB)->ResultStatus = status;
3189         osi_Log2(afsd_logp, "RDR_FlushFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
3190                   code, status);
3191         return;
3192     }
3193
3194     lock_ObtainWrite(&scp->rw);
3195     if (scp->flags & CM_SCACHEFLAG_DELETED) {
3196         lock_ReleaseWrite(&scp->rw);
3197         (*ResultCB)->ResultStatus = STATUS_INVALID_HANDLE;
3198         return;
3199     }
3200
3201     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3202                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3203     if (code) {
3204         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3205         (*ResultCB)->ResultStatus = status;
3206         lock_ReleaseWrite(&scp->rw);
3207         cm_ReleaseSCache(scp);
3208         osi_Log3(afsd_logp, "RDR_FlushFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
3209                  scp, code, status);
3210         return;
3211     }
3212
3213     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3214     lock_ReleaseWrite(&scp->rw);
3215
3216     code = cm_FSync(scp, userp, &req, FALSE);
3217     cm_ReleaseSCache(scp);
3218
3219     if (code) {
3220         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3221         (*ResultCB)->ResultStatus = status;
3222         osi_Log2(afsd_logp, "RDR_FlushFileEntry FAILURE code=0x%x status=0x%x",
3223                   code, status);
3224     } else {
3225         (*ResultCB)->ResultStatus = 0;
3226         osi_Log0(afsd_logp, "RDR_FlushFileEntry SUCCESS");
3227     }
3228     (*ResultCB)->ResultBufferLength = 0;
3229
3230     return;
3231 }
3232
3233 afs_uint32
3234 RDR_CheckAccess( IN cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
3235                  ULONG access,
3236                  ULONG *granted)
3237 {
3238     ULONG afs_acc, afs_gr;
3239     BOOLEAN file, dir;
3240     afs_uint32 code = 0;
3241
3242     file = (scp->fileType == CM_SCACHETYPE_FILE);
3243     dir = !file;
3244
3245     /* access definitions from prs_fs.h */
3246     afs_acc = 0;
3247     if (access & FILE_READ_DATA)
3248         afs_acc |= PRSFS_READ;
3249     if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
3250         afs_acc |= PRSFS_READ;
3251     if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
3252         afs_acc |= PRSFS_WRITE;
3253     if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
3254         afs_acc |= PRSFS_WRITE;
3255     if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
3256         afs_acc |= PRSFS_INSERT;
3257     if (dir && (access & FILE_LIST_DIRECTORY))
3258         afs_acc |= PRSFS_LOOKUP;
3259     if (file && (access & FILE_EXECUTE))
3260         afs_acc |= PRSFS_WRITE;
3261     if (dir && (access & FILE_TRAVERSE))
3262         afs_acc |= PRSFS_READ;
3263     if (dir && (access & FILE_DELETE_CHILD))
3264         afs_acc |= PRSFS_DELETE;
3265     if ((access & DELETE))
3266         afs_acc |= PRSFS_DELETE;
3267
3268     /* check ACL with server */
3269     lock_ObtainWrite(&scp->rw);
3270     while (1)
3271     {
3272         if (cm_HaveAccessRights(scp, userp, reqp, afs_acc, &afs_gr))
3273         {
3274             break;
3275         }
3276         else
3277         {
3278             /* we don't know the required access rights */
3279             code = cm_GetAccessRights(scp, userp, reqp);
3280             if (code)
3281                 break;
3282             continue;
3283         }
3284     }
3285     lock_ReleaseWrite(&(scp->rw));
3286
3287     if (code == 0) {
3288         *granted = 0;
3289         if (afs_gr & PRSFS_READ)
3290             *granted |= FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE;
3291         if (afs_gr & PRSFS_WRITE)
3292             *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE;
3293         if (afs_gr & PRSFS_INSERT)
3294             *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
3295         if (afs_gr & PRSFS_LOOKUP)
3296             *granted |= (dir ? FILE_LIST_DIRECTORY : 0);
3297         if (afs_gr & PRSFS_DELETE)
3298             *granted |= FILE_DELETE_CHILD | DELETE;
3299         if (afs_gr & PRSFS_LOCK)
3300             *granted |= 0;
3301         if (afs_gr & PRSFS_ADMINISTER)
3302             *granted |= 0;
3303
3304         *granted |= SYNCHRONIZE | READ_CONTROL;
3305
3306         /* don't give more access than what was requested */
3307         *granted &= access;
3308         osi_Log3(afsd_logp, "RDR_CheckAccess SUCCESS scp=0x%p requested=0x%x granted=0x%x", scp, access, *granted);
3309     } else
3310         osi_Log2(afsd_logp, "RDR_CheckAccess FAILURE scp=0x%p code=0x%x",
3311                  scp, code);
3312
3313     return code;
3314 }
3315
3316 void
3317 RDR_OpenFileEntry( IN cm_user_t *userp,
3318                    IN AFSFileID FileId,
3319                    IN AFSFileOpenCB *OpenCB,
3320                    IN BOOL bWow64,
3321                    IN BOOL bHoldFid,
3322                    IN DWORD ResultBufferLength,
3323                    IN OUT AFSCommResult **ResultCB)
3324 {
3325     AFSFileOpenResultCB *pResultCB = NULL;
3326     cm_scache_t *scp = NULL;
3327     cm_user_t   *sysUserp = NULL;
3328     cm_fid_t    Fid;
3329     cm_lock_data_t      *ldp = NULL;
3330     afs_uint32  code;
3331     cm_req_t    req;
3332     DWORD       status;
3333
3334     RDR_InitReq(&req, bWow64);
3335
3336     osi_Log4(afsd_logp, "RDR_OpenFileEntry File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3337               FileId.Cell, FileId.Volume,
3338               FileId.Vnode, FileId.Unique);
3339
3340     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
3341     if (!(*ResultCB)) {
3342         osi_Log0(afsd_logp, "RDR_OpenFileEntry out of memory");
3343         return;
3344     }
3345
3346     memset( *ResultCB,
3347             '\0',
3348             sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
3349
3350     pResultCB = (AFSFileOpenResultCB *)(*ResultCB)->ResultData;
3351
3352     /* Process the release */
3353     Fid.cell = FileId.Cell;
3354     Fid.volume = FileId.Volume;
3355     Fid.vnode = FileId.Vnode;
3356     Fid.unique = FileId.Unique;
3357     Fid.hash = FileId.Hash;
3358
3359     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3360     if (code) {
3361         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3362         (*ResultCB)->ResultStatus = status;
3363         osi_Log2(afsd_logp, "RDR_OpenFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
3364                   code, status);
3365         return;
3366     }
3367
3368     lock_ObtainWrite(&scp->rw);
3369     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3370                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3371     if (code) {
3372         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3373         (*ResultCB)->ResultStatus = status;
3374         lock_ReleaseWrite(&scp->rw);
3375         cm_ReleaseSCache(scp);
3376         osi_Log3(afsd_logp, "RDR_OpenFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
3377                  scp, code, status);
3378         return;
3379     }
3380
3381     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3382     lock_ReleaseWrite(&scp->rw);
3383
3384     sysUserp = RDR_GetLocalSystemUser();
3385
3386     /*
3387      * Skip the open check if the request is coming from the local system account.
3388      * The local system has no tokens and therefore any requests sent to a file
3389      * server will fail.  Unfortunately, there are special system processes that
3390      * perform actions on files and directories in preparation for memory mapping
3391      * executables.  If the open check fails, the real request from the user process
3392      * will never be issued.
3393      *
3394      * Permitting the file system to allow subsequent operations to proceed does
3395      * not compromise security.  All requests to obtain file data or directory
3396      * enumerations will subsequently fail if they are not submitted under the
3397      * context of a process for that have access to the necessary credentials.
3398      */
3399
3400     if ( userp == sysUserp)
3401     {
3402         osi_Log1(afsd_logp, "RDR_OpenFileEntry LOCAL_SYSTEM access check skipped scp=0x%p",
3403                  scp);
3404         pResultCB->GrantedAccess = OpenCB->DesiredAccess;
3405         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3406         code = 0;
3407     }
3408     else
3409     {
3410         int count = 0;
3411
3412         do {
3413             if (count++ > 0) {
3414                 Sleep(350);
3415                 osi_Log3(afsd_logp,
3416                          "RDR_OpenFileEntry repeating open check scp=0x%p userp=0x%p code=0x%x",
3417                          scp, userp, code);
3418             }
3419             code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OpenCB->ShareAccess,
3420                                   OPEN_ALWAYS,
3421                                   OpenCB->ProcessId, OpenCB->Identifier,
3422                                   userp, &req, &ldp);
3423             if (code == 0)
3424                 code = RDR_CheckAccess(scp, userp, &req, OpenCB->DesiredAccess, &pResultCB->GrantedAccess);
3425
3426
3427             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
3428         } while (count < 100 && (code == CM_ERROR_RETRY || code == CM_ERROR_WOULDBLOCK));
3429     }
3430
3431     /*
3432      * If we are restricting sharing, we should do so with a suitable
3433      * share lock.
3434      */
3435     if (code == 0 && scp->fileType == CM_SCACHETYPE_FILE && !(OpenCB->ShareAccess & FILE_SHARE_WRITE)) {
3436         cm_key_t key;
3437         LARGE_INTEGER LOffset, LLength;
3438         int sLockType;
3439
3440         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
3441         LOffset.LowPart = SMB_FID_QLOCK_LOW;
3442         LLength.HighPart = 0;
3443         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
3444
3445         /*
3446          * If we are not opening the file for writing, then we don't
3447          * try to get an exclusive lock.  No one else should be able to
3448          * get an exclusive lock on the file anyway, although someone
3449          * else can get a shared lock.
3450          */
3451         if ((OpenCB->ShareAccess & FILE_SHARE_READ) || !(OpenCB->DesiredAccess & AFS_ACCESS_WRITE))
3452         {
3453             sLockType = LOCKING_ANDX_SHARED_LOCK;
3454         } else {
3455             sLockType = 0;
3456         }
3457
3458         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, OpenCB->Identifier);
3459
3460         lock_ObtainWrite(&scp->rw);
3461         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
3462         lock_ReleaseWrite(&scp->rw);
3463
3464         if (code) {
3465             code = CM_ERROR_SHARING_VIOLATION;
3466             pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3467         } else {
3468             if (sLockType == LOCKING_ANDX_SHARED_LOCK)
3469                 pResultCB->FileAccess = AFS_FILE_ACCESS_SHARED;
3470             else
3471                 pResultCB->FileAccess = AFS_FILE_ACCESS_EXCLUSIVE;
3472         }
3473     } else {
3474         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3475     }
3476
3477     cm_ReleaseUser(sysUserp);
3478     if (code == 0 && bHoldFid)
3479         RDR_FlagScpInUse( scp, FALSE );
3480     cm_ReleaseSCache(scp);
3481
3482     if (code) {
3483         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3484         (*ResultCB)->ResultStatus = status;
3485         osi_Log2(afsd_logp, "RDR_OpenFileEntry FAILURE code=0x%x status=0x%x",
3486                   code, status);
3487     } else {
3488         (*ResultCB)->ResultStatus = 0;
3489         (*ResultCB)->ResultBufferLength = sizeof( AFSFileOpenResultCB);
3490         osi_Log0(afsd_logp, "RDR_OpenFileEntry SUCCESS");
3491     }
3492     return;
3493 }
3494
3495 void
3496 RDR_ReleaseFileAccess( IN cm_user_t *userp,
3497                        IN AFSFileID FileId,
3498                        IN AFSFileAccessReleaseCB *ReleaseFileCB,
3499                        IN BOOL bWow64,
3500                        IN DWORD ResultBufferLength,
3501                        IN OUT AFSCommResult **ResultCB)
3502 {
3503     cm_key_t key;
3504     unsigned int sLockType;
3505     LARGE_INTEGER LOffset, LLength;
3506     cm_scache_t *scp = NULL;
3507     cm_fid_t    Fid;
3508     afs_uint32  code;
3509     cm_req_t    req;
3510     DWORD       status;
3511
3512     RDR_InitReq(&req, bWow64);
3513
3514     osi_Log4(afsd_logp, "RDR_ReleaseFileAccess File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3515               FileId.Cell, FileId.Volume,
3516               FileId.Vnode, FileId.Unique);
3517
3518     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
3519     if (!(*ResultCB)) {
3520         osi_Log0(afsd_logp, "RDR_ReleaseFileAccess out of memory");
3521         return;
3522     }
3523
3524     memset( *ResultCB, '\0', sizeof( AFSCommResult));
3525
3526     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_NOLOCK)
3527         return;
3528
3529     /* Process the release */
3530     Fid.cell = FileId.Cell;
3531     Fid.volume = FileId.Volume;
3532     Fid.vnode = FileId.Vnode;
3533     Fid.unique = FileId.Unique;
3534     Fid.hash = FileId.Hash;
3535
3536     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3537     if (code) {
3538         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3539         (*ResultCB)->ResultStatus = status;
3540         osi_Log2(afsd_logp, "RDR_ReleaseFileAccess cm_GetSCache FID failure code=0x%x status=0x%x",
3541                   code, status);
3542         return;
3543     }
3544
3545     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_SHARED)
3546         sLockType = LOCKING_ANDX_SHARED_LOCK;
3547     else
3548         sLockType = 0;
3549
3550     key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, ReleaseFileCB->Identifier);
3551
3552     LOffset.HighPart = SMB_FID_QLOCK_HIGH;
3553     LOffset.LowPart = SMB_FID_QLOCK_LOW;
3554     LLength.HighPart = 0;
3555     LLength.LowPart = SMB_FID_QLOCK_LENGTH;
3556
3557     lock_ObtainWrite(&scp->rw);
3558
3559     code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
3560     if (code == 0)
3561     {
3562         code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
3563
3564         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
3565
3566         if (code == CM_ERROR_RANGE_NOT_LOCKED)
3567         {
3568             osi_Log3(afsd_logp, "RDR_ReleaseFileAccess Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
3569                      ReleaseFileCB->FileAccess, ReleaseFileCB->ProcessId, ReleaseFileCB->Identifier);
3570         }
3571     }
3572
3573     lock_ReleaseWrite(&scp->rw);
3574
3575     osi_Log0(afsd_logp, "RDR_ReleaseFileAccessEntry SUCCESS");
3576 }
3577
3578 static const char *
3579 HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
3580 {
3581     int i, k;
3582     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
3583
3584     if (buflen < 33)
3585         return "buffer length too small to HexCheckSum";
3586
3587     for (i=0;i<16;i++) {
3588         k = md5cksum[i];
3589
3590         buf[i*2] = tr[k / 16];
3591         buf[i*2+1] = tr[k % 16];
3592     }
3593     buf[32] = '\0';
3594
3595     return buf;
3596 }
3597
3598 /*
3599  * Extent requests from the file system are triggered when a file
3600  * page is not resident in the Windows cache.  The file system is
3601  * responsible for loading the page but cannot block the request
3602  * while doing so.  The AFS Redirector forwards the requests to
3603  * the AFS cache manager while indicating to Windows that the page
3604  * is not yet available.  A polling operation will then ensue with
3605  * the AFS Redirector issuing a RDR_RequestFileExtentsXXX call for
3606  * each poll attempt.  As each request is received and processed
3607  * by a separate worker thread in the service, this can lead to
3608  * contention by multiple threads attempting to claim the same
3609  * cm_buf_t objects.  Therefore, it is important that
3610  *
3611  *  (a) the service avoid processing more than one overlapping
3612  *      extent request at a time
3613  *  (b) background daemon processing be used to avoid blocking
3614  *      of ioctl threads
3615  *
3616  * Beginning with the 20091122 build of the redirector, the redirector
3617  * will not issue an additional RDR_RequestFileExtentsXXX call for
3618  * each poll request.  Instead, afsd_service is required to track
3619  * the requests and return them to the redirector or fail the
3620  * portions of the request that cannot be satisfied.
3621  *
3622  * The request processing returns any extents that can be returned
3623  * immediately to the redirector.  The rest of the requested range(s)
3624  * are queued as background operations using RDR_BkgFetch().
3625  */
3626
3627 /* do the background fetch. */
3628 afs_int32
3629 RDR_BkgFetch(cm_scache_t *scp, void *rockp, cm_user_t *userp, cm_req_t *reqp)
3630 {
3631     osi_hyper_t length;
3632     osi_hyper_t base;
3633     osi_hyper_t offset;
3634     osi_hyper_t end;
3635     osi_hyper_t fetched;
3636     osi_hyper_t tblocksize;
3637     afs_int32 code;
3638     int rwheld = 0;
3639     cm_buf_t *bufp = NULL;
3640     DWORD dwResultBufferLength;
3641     AFSSetFileExtentsCB *pResultCB;
3642     DWORD status;
3643     afs_uint32 count=0;
3644     AFSFileID FileId;
3645     int reportErrorToRedir = 0;
3646     int force_retry = 0;
3647
3648     FileId.Cell = scp->fid.cell;
3649     FileId.Volume = scp->fid.volume;
3650     FileId.Vnode = scp->fid.vnode;
3651     FileId.Unique = scp->fid.unique;
3652     FileId.Hash = scp->fid.hash;
3653
3654     fetched.LowPart = 0;
3655     fetched.HighPart = 0;
3656     tblocksize = ConvertLongToLargeInteger(cm_data.buf_blockSize);
3657     base = ((rock_BkgFetch_t *)rockp)->base;
3658     length = ((rock_BkgFetch_t *)rockp)->length;
3659     end = LargeIntegerAdd(base, length);
3660
3661     osi_Log5(afsd_logp, "Starting BKG Fetch scp 0x%p offset 0x%x:%x length 0x%x:%x",
3662              scp, base.HighPart, base.LowPart, length.HighPart, length.LowPart);
3663
3664     /*
3665      * Make sure we have a callback.
3666      * This is necessary so that we can return access denied
3667      * if a callback cannot be granted.
3668      */
3669     lock_ObtainWrite(&scp->rw);
3670     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_READ,
3671                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3672     if (code) {
3673         lock_ReleaseWrite(&scp->rw);
3674         osi_Log2(afsd_logp, "RDR_BkgFetch cm_SyncOp failure scp=0x%p code=0x%x",
3675                  scp, code);
3676         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
3677         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3678         return code;
3679     }
3680     lock_ReleaseWrite(&scp->rw);
3681
3682     dwResultBufferLength = (DWORD)(sizeof( AFSSetFileExtentsCB) + sizeof( AFSFileExtentCB) * (length.QuadPart / cm_data.blockSize + 1));
3683     pResultCB = (AFSSetFileExtentsCB *)malloc( dwResultBufferLength );
3684     if (!pResultCB)
3685         return CM_ERROR_RETRY;
3686
3687     memset( pResultCB, '\0', dwResultBufferLength );
3688     pResultCB->FileId = FileId;
3689
3690     for ( code = 0, offset = base;
3691           code == 0 && LargeIntegerLessThan(offset, end);
3692           offset = LargeIntegerAdd(offset, tblocksize) )
3693     {
3694         int bBufRelease = TRUE;
3695
3696         if (rwheld) {
3697             lock_ReleaseWrite(&scp->rw);
3698             rwheld = 0;
3699         }
3700
3701         code = buf_Get(scp, &offset, reqp, 0, &bufp);
3702         if (code) {
3703             /*
3704              * any error from buf_Get() is non-fatal.
3705              * we need to re-queue this extent fetch.
3706              */
3707             force_retry = 1;
3708             break;
3709         }
3710
3711         if (!rwheld) {
3712             lock_ObtainWrite(&scp->rw);
3713             rwheld = 1;
3714         }
3715
3716         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
3717         if (code == 0) {
3718             if (!(bufp->qFlags & CM_BUF_QREDIR)) {
3719 #ifdef VALIDATE_CHECK_SUM
3720 #ifdef ODS_DEBUG
3721                 char md5dbg[33];
3722                 char dbgstr[1024];
3723 #endif
3724 #endif
3725                 if (bufp->flags & CM_BUF_DIRTY)
3726                     cm_BufWrite(scp, &bufp->offset, cm_data.buf_blockSize, CM_BUF_WRITE_SCP_LOCKED, userp, reqp);
3727
3728                 lock_ObtainWrite(&buf_globalLock);
3729                 if (!(bufp->flags & CM_BUF_DIRTY) &&
3730                     bufp->cmFlags == 0 &&
3731                     !(bufp->qFlags & CM_BUF_QREDIR)) {
3732                     buf_InsertToRedirQueue(scp, bufp);
3733                     lock_ReleaseWrite(&buf_globalLock);
3734
3735 #ifdef VALIDATE_CHECK_SUM
3736                     buf_ComputeCheckSum(bufp);
3737 #endif
3738                     pResultCB->FileExtents[count].Flags = 0;
3739                     pResultCB->FileExtents[count].FileOffset.QuadPart = bufp->offset.QuadPart;
3740                     pResultCB->FileExtents[count].CacheOffset.QuadPart = bufp->datap - RDR_extentBaseAddress;
3741                     pResultCB->FileExtents[count].Length = cm_data.blockSize;
3742                     count++;
3743                     fetched = LargeIntegerAdd(fetched, tblocksize);
3744                     bBufRelease = FALSE;
3745
3746 #ifdef VALIDATE_CHECK_SUM
3747 #ifdef ODS_DEBUG
3748                     HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
3749                     snprintf( dbgstr, 1024,
3750                               "RDR_BkgFetch md5 %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3751                               md5dbg,
3752                               scp->fid.volume, scp->fid.vnode, scp->fid.unique,
3753                               pResultCB->FileExtents[count].FileOffset.HighPart,
3754                               pResultCB->FileExtents[count].FileOffset.LowPart,
3755                               pResultCB->FileExtents[count].CacheOffset.HighPart,
3756                               pResultCB->FileExtents[count].CacheOffset.LowPart);
3757                     OutputDebugStringA( dbgstr);
3758 #endif
3759 #endif
3760                     osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3761                               bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3762                 } else {
3763                     lock_ReleaseWrite(&buf_globalLock);
3764                     if ((bufp->cmFlags != 0) || (bufp->flags & CM_BUF_DIRTY)) {
3765                         /* An I/O operation is already in progress */
3766                         force_retry = 1;
3767                         osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Not delivering to Redirector Dirty or Busy bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3768                                   bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3769                     } else {
3770                         osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3771                                   bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3772                     }
3773                 }
3774             } else {
3775                 osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3776                           bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3777             }
3778         } else {
3779             /*
3780              * depending on what the error from cm_GetBuffer is
3781              * it may or may not be fatal.  Only return fatal errors.
3782              * Re-queue a request for others.
3783              */
3784             osi_Log5(afsd_logp, "RDR_BkgFetch Extent2FS FAILURE bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x code 0x%x",
3785                       bufp, offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize, code);
3786             switch (code) {
3787             case CM_ERROR_NOACCESS:
3788             case CM_ERROR_NOSUCHFILE:
3789             case CM_ERROR_NOSUCHPATH:
3790             case CM_ERROR_NOSUCHVOLUME:
3791             case CM_ERROR_NOSUCHCELL:
3792             case CM_ERROR_INVAL:
3793             case CM_ERROR_BADFD:
3794             case CM_ERROR_CLOCKSKEW:
3795             case RXKADNOAUTH:
3796             case CM_ERROR_QUOTA:
3797             case CM_ERROR_LOCK_CONFLICT:
3798             case EIO:
3799             case CM_ERROR_INVAL_NET_RESP:
3800             case CM_ERROR_UNKNOWN:
3801                 /*
3802                  * these are fatal errors.  deliver what we can
3803                  * and halt.
3804                  */
3805                 reportErrorToRedir = 1;
3806                 break;
3807             default:
3808                 /*
3809                  * non-fatal errors.  re-queue the exent
3810                  */
3811                 code = CM_ERROR_RETRY;
3812                 force_retry = 1;
3813             }
3814         }
3815
3816         if (bBufRelease)
3817             buf_Release(bufp);
3818     }
3819
3820     if (!rwheld) {
3821         lock_ObtainWrite(&scp->rw);
3822         rwheld = 1;
3823     }
3824
3825     /* wakeup anyone who is waiting */
3826     if (scp->flags & CM_SCACHEFLAG_WAITING) {
3827         osi_Log1(afsd_logp, "RDR Bkg Fetch Waking scp 0x%p", scp);
3828         osi_Wakeup((LONG_PTR) &scp->flags);
3829     }
3830     lock_ReleaseWrite(&scp->rw);
3831
3832     if (count > 0) {
3833         pResultCB->ExtentCount = count;
3834         RDR_SetFileExtents( pResultCB, dwResultBufferLength);
3835     }
3836     free(pResultCB);
3837
3838     if (reportErrorToRedir) {
3839         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
3840         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3841     }
3842
3843     osi_Log4(afsd_logp, "Ending BKG Fetch scp 0x%p code 0x%x fetched 0x%x:%x",
3844              scp, code, fetched.HighPart, fetched.LowPart);
3845
3846     return force_retry ? CM_ERROR_RETRY : code;
3847 }
3848
3849
3850 BOOL
3851 RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
3852                              IN AFSFileID FileId,
3853                              IN AFSRequestExtentsCB *RequestExtentsCB,
3854                              IN BOOL bWow64,
3855                              IN OUT DWORD * ResultBufferLength,
3856                              IN OUT AFSSetFileExtentsCB **ResultCB)
3857 {
3858     AFSSetFileExtentsCB *pResultCB = NULL;
3859     DWORD Length;
3860     DWORD count;
3861     DWORD status;
3862     cm_scache_t *scp = NULL;
3863     cm_fid_t    Fid;
3864     cm_buf_t    *bufp;
3865     afs_uint32  code = 0;
3866     osi_hyper_t thyper;
3867     LARGE_INTEGER ByteOffset, BeginOffset, EndOffset, QueueOffset;