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