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