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