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