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