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