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