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