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