35031549d35c1a0cda3377b1cd455d3f3bf7ae85
[openafs.git] / src / WINNT / afsrdr / user / RDRFunction.c
1 /*
2  * Copyright (c) 2008 Secure Endpoints, Inc.
3  * Copyright (c) 2009-2013 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  *   this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  * - Neither the name of Secure Endpoints Inc. nor the names of its contributors
15  *   may be used to endorse or promote products derived from this software without
16  *   specific prior written permission from Secure Endpoints, Inc. and
17  *   Your File System, Inc.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
23  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <afsconfig.h>
33 #include <afs/param.h>
34
35 #ifndef _WIN32_WINNT
36 #define _WIN32_WINNT 0x0500
37 #endif
38 #define _CRT_SECURE_NO_DEPRECATE
39 #define _CRT_NON_CONFORMING_SWPRINTFS
40 #define INITGUID        /* define AFS_AUTH_GUID_NO_PAG */
41
42 #include <ntstatus.h>
43 #define WIN32_NO_STATUS
44 #include <windows.h>
45
46 #include <roken.h>
47
48 #include <afs/stds.h>
49
50 #include <ntsecapi.h>
51 #include <sddl.h>
52 #pragma warning(push)
53 #pragma warning(disable: 4005)
54
55 #include <devioctl.h>
56
57 #include "..\\Common\\AFSUserDefines.h"
58 #include "..\\Common\\AFSUserStructs.h"
59
60 #pragma warning(pop)
61
62 #include <tchar.h>
63 #include <wchar.h>
64 #include <winbase.h>
65 #include <winreg.h>
66
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <stdarg.h>
70 #include <strsafe.h>
71
72 #include "afsd.h"
73 #include "smb.h"
74 #include "cm_btree.h"
75 #include "msrpc.h"
76 #include <RDRPrototypes.h>
77 #include <RDRIoctl.h>
78 #include <RDRPipe.h>
79
80 static CHAR * RDR_extentBaseAddress = NULL;
81
82 void
83 RDR_InitReq(cm_req_t *reqp, BOOL bWow64)
84 {
85     cm_InitReq(reqp);
86     reqp->flags |= CM_REQ_SOURCE_REDIR;
87     if (bWow64)
88         reqp->flags |= CM_REQ_WOW64;
89 }
90
91 void
92 RDR_fid2FID( cm_fid_t *fid, AFSFileID *FileId)
93 {
94     FileId->Cell = fid->cell;
95     FileId->Volume = fid->volume;
96     FileId->Vnode = fid->vnode;
97     FileId->Unique = fid->unique;
98     FileId->Hash = fid->hash;
99 }
100
101 void
102 RDR_FID2fid( AFSFileID *FileId, cm_fid_t *fid)
103 {
104     fid->cell = FileId->Cell;
105     fid->volume = FileId->Volume;
106     fid->vnode = FileId->Vnode;
107     fid->unique = FileId->Unique;
108     fid->hash = FileId->Hash;
109 }
110
111 DWORD
112 RDR_SetInitParams( OUT AFSRedirectorInitInfo **ppRedirInitInfo, OUT DWORD * pRedirInitInfoLen )
113 {
114     extern char cm_CachePath[];
115     extern cm_config_data_t cm_data;
116     extern int smb_hideDotFiles;
117     size_t CachePathLen;
118     DWORD TempPathLen;
119     size_t err;
120     MEMORYSTATUSEX memStatus;
121     DWORD maxMemoryCacheSize;
122     char FullCachePath[MAX_PATH];
123     char TempPath[MAX_PATH];
124     char FullTempPath[MAX_PATH];
125
126     /*
127      * The %TEMP% environment variable may be relative instead
128      * of absolute which can result in the redirector referring
129      * to a different directory than the service.  The full path
130      * must therefore be obtained first.
131      */
132
133     CachePathLen = GetFullPathNameA(cm_CachePath, MAX_PATH, FullCachePath, NULL);
134     if (CachePathLen == 0) {
135         osi_Log0(afsd_logp, "RDR_SetInitParams Unable to obtain Full Cache Path");
136         return STATUS_OBJECT_NAME_NOT_FOUND;
137     }
138
139     TempPathLen = ExpandEnvironmentStringsA("%TEMP%", TempPath, MAX_PATH);
140     if (TempPathLen == 0) {
141         osi_Log0(afsd_logp, "RDR_SetInitParams Unable to expand %%TEMP%%");
142         return STATUS_OBJECT_NAME_NOT_FOUND;
143     }
144
145     TempPathLen = GetFullPathNameA(TempPath, MAX_PATH, FullTempPath, NULL);
146     if (TempPathLen == 0) {
147         osi_Log0(afsd_logp, "RDR_SetInitParams Unable to obtain Full Temp Path");
148         return STATUS_OBJECT_NAME_NOT_FOUND;
149     }
150
151     memStatus.dwLength = sizeof(memStatus);
152     if (GlobalMemoryStatusEx(&memStatus)) {
153         /*
154          * Use the memory extent interface in the afs redirector
155          * whenever the cache size is less than equal to 10% of
156          * physical memory.  Do not use too much because this memory
157          * will be locked by the redirector so it can't be swapped
158          * out.
159          */
160         maxMemoryCacheSize = (DWORD)(memStatus.ullTotalPhys / 1024 / 10);
161     } else {
162         /*
163          * If we can't determine the amount of physical memory
164          * in the system, be conservative and limit the use of
165          * memory extent interface to 64MB data caches.
166          */
167         maxMemoryCacheSize = 65536;
168     }
169
170     *pRedirInitInfoLen = (DWORD) (sizeof(AFSRedirectorInitInfo) + (CachePathLen + TempPathLen) * sizeof(WCHAR));
171     *ppRedirInitInfo = (AFSRedirectorInitInfo *)malloc(*pRedirInitInfoLen);
172     (*ppRedirInitInfo)->Flags = smb_hideDotFiles ? AFS_REDIR_INIT_FLAG_HIDE_DOT_FILES : 0;
173     (*ppRedirInitInfo)->Flags |= cm_shortNames ? 0 : AFS_REDIR_INIT_FLAG_DISABLE_SHORTNAMES;
174     (*ppRedirInitInfo)->Flags |= cm_directIO ? AFS_REDIR_INIT_PERFORM_SERVICE_IO : 0;
175     (*ppRedirInitInfo)->MaximumChunkLength = cm_data.chunkSize;
176     (*ppRedirInitInfo)->GlobalFileId.Cell   = cm_data.rootFid.cell;
177     (*ppRedirInitInfo)->GlobalFileId.Volume = cm_data.rootFid.volume;
178     (*ppRedirInitInfo)->GlobalFileId.Vnode  = cm_data.rootFid.vnode;
179     (*ppRedirInitInfo)->GlobalFileId.Unique = cm_data.rootFid.unique;
180     (*ppRedirInitInfo)->GlobalFileId.Hash   = cm_data.rootFid.hash;
181     (*ppRedirInitInfo)->ExtentCount.QuadPart = cm_data.buf_nbuffers;
182     (*ppRedirInitInfo)->CacheBlockSize = cm_data.blockSize;
183     (*ppRedirInitInfo)->MaxPathLinkCount = MAX_FID_COUNT;
184     (*ppRedirInitInfo)->NameArrayLength = MAX_FID_COUNT;
185     if (cm_virtualCache || cm_data.bufferSize <= maxMemoryCacheSize) {
186         osi_Log0(afsd_logp, "RDR_SetInitParams Initializing Memory Extent Interface");
187         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = (LONGLONG)cm_data.bufDataBaseAddress;
188         (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = cm_data.bufEndOfData - cm_data.bufDataBaseAddress;
189         (*ppRedirInitInfo)->CacheFileNameLength = 0;
190         RDR_extentBaseAddress = cm_data.bufDataBaseAddress;
191     } else {
192         (*ppRedirInitInfo)->MemoryCacheOffset.QuadPart = 0;
193         (*ppRedirInitInfo)->MemoryCacheLength.QuadPart = 0;
194         (*ppRedirInitInfo)->CacheFileNameLength = (ULONG) (CachePathLen * sizeof(WCHAR));
195         err = mbstowcs((*ppRedirInitInfo)->CacheFileName, FullCachePath, (CachePathLen + 1) *sizeof(WCHAR));
196         if (err == -1) {
197             free(*ppRedirInitInfo);
198             osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
199             return STATUS_OBJECT_NAME_INVALID;
200         }
201         RDR_extentBaseAddress = cm_data.baseAddress;
202     }
203     (*ppRedirInitInfo)->DumpFileLocationOffset = FIELD_OFFSET(AFSRedirectorInitInfo, CacheFileName) + (*ppRedirInitInfo)->CacheFileNameLength;
204     (*ppRedirInitInfo)->DumpFileLocationLength = (TempPathLen - 1) * sizeof(WCHAR);
205
206     err = mbstowcs((((PBYTE)(*ppRedirInitInfo)) + (*ppRedirInitInfo)->DumpFileLocationOffset),
207                    FullTempPath, (TempPathLen + 1) *sizeof(WCHAR));
208     if (err == -1) {
209         free(*ppRedirInitInfo);
210         osi_Log0(afsd_logp, "RDR_SetInitParams Invalid Object Name");
211         return STATUS_OBJECT_NAME_INVALID;
212     }
213
214     osi_Log0(afsd_logp,"RDR_SetInitParams Success");
215     return 0;
216 }
217
218 static wchar_t cname[MAX_COMPUTERNAME_LENGTH+1] = L"";
219
220 cm_user_t *
221 RDR_GetLocalSystemUser( void)
222 {
223     smb_username_t *unp;
224     cm_user_t *userp = NULL;
225
226     if ( cname[0] == '\0') {
227         int len = MAX_COMPUTERNAME_LENGTH+1;
228         GetComputerNameW(cname, &len);
229         _wcsupr(cname);
230     }
231     unp = smb_FindUserByName(NTSID_LOCAL_SYSTEM, cname, SMB_FLAG_CREATE);
232     lock_ObtainMutex(&unp->mx);
233     if (!unp->userp)
234         unp->userp = cm_NewUser();
235     unp->flags |= SMB_USERNAMEFLAG_SID;
236     lock_ReleaseMutex(&unp->mx);
237     userp = unp->userp;
238     cm_HoldUser(userp);
239     smb_ReleaseUsername(unp);
240
241     if (!userp) {
242         userp = cm_rootUserp;
243         cm_HoldUser(userp);
244     }
245
246     return userp;
247 }
248
249 cm_user_t *
250 RDR_UserFromCommRequest( IN AFSCommRequest *RequestBuffer)
251 {
252
253     return RDR_UserFromAuthGroup( &RequestBuffer->AuthGroup);
254 }
255
256 cm_user_t *
257 RDR_UserFromAuthGroup( IN GUID *pGuid)
258 {
259     smb_username_t *unp;
260     cm_user_t * userp = NULL;
261     RPC_WSTR UuidString = NULL;
262
263     if (UuidToStringW((UUID *)pGuid, &UuidString) != RPC_S_OK)
264         goto done;
265
266     if ( cname[0] == '\0') {
267         int len = MAX_COMPUTERNAME_LENGTH+1;
268         GetComputerNameW(cname, &len);
269         _wcsupr(cname);
270     }
271
272     unp = smb_FindUserByName(UuidString, cname, SMB_FLAG_CREATE);
273     lock_ObtainMutex(&unp->mx);
274     if (!unp->userp) {
275         unp->userp = cm_NewUser();
276         memcpy(&unp->userp->authgroup, pGuid, sizeof(GUID));
277     }
278     unp->flags |= SMB_USERNAMEFLAG_SID;
279     lock_ReleaseMutex(&unp->mx);
280     userp = unp->userp;
281     cm_HoldUser(userp);
282     smb_ReleaseUsername(unp);
283
284   done:
285     if (!userp) {
286         userp = cm_rootUserp;
287         cm_HoldUser(userp);
288     }
289
290     osi_Log2(afsd_logp, "RDR_UserFromCommRequest Guid %S userp = 0x%p",
291              osi_LogSaveStringW(afsd_logp, UuidString),
292              userp);
293
294     if (UuidString)
295         RpcStringFreeW(&UuidString);
296
297     return userp;
298 }
299
300 void
301 RDR_ReleaseUser( IN cm_user_t *userp )
302 {
303     osi_Log1(afsd_logp, "RDR_ReleaseUser userp = 0x%p", userp);
304     cm_ReleaseUser(userp);
305 }
306
307
308 /*
309  * RDR_FlagScpInUse flags the scp with CM_SCACHEFLAG_RDR_IN_USE
310  */
311 static void
312 RDR_FlagScpInUse( IN cm_scache_t *scp, IN BOOL bLocked )
313 {
314     if (!bLocked)
315         lock_ObtainWrite(&scp->rw);
316
317     lock_AssertWrite(&scp->rw);
318     scp->flags |= CM_SCACHEFLAG_RDR_IN_USE;
319
320     if (!bLocked)
321         lock_ReleaseWrite(&scp->rw);
322 }
323
324 /*
325  * Obtain the status information for the specified object using
326  * an inline bulk status rpc.  cm_BPlusDirEnumBulkStatOne() will
327  * obtain current status for the directory object, the object
328  * which is the focus of the inquiry and as many other objects
329  * in the directory for which there are not callbacks registered
330  * since we are likely to be asked for other objects in the directory.
331  */
332 static afs_uint32
333 RDR_BulkStatLookup( cm_scache_t *dscp,
334                     cm_scache_t *scp,
335                     cm_user_t   *userp,
336                     cm_req_t    *reqp)
337 {
338     cm_direnum_t *      enump = NULL;
339     afs_uint32  code = 0;
340     cm_dirOp_t    dirop;
341
342     code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
343     if (code == 0) {
344         code = cm_BPlusDirEnumerate(dscp, userp, reqp, TRUE, NULL, TRUE, &enump);
345         if (code) {
346             osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumerate failure code=0x%x",
347                       code);
348         }
349         cm_EndDirOp(&dirop);
350     } else {
351         osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BeginDirOp failure code=0x%x",
352                   code);
353     }
354
355     if (enump)
356     {
357         code = cm_BPlusDirEnumBulkStatOne(enump, scp);
358         if (code) {
359             osi_Log1(afsd_logp, "RDR_BulkStatLookup cm_BPlusDirEnumBulkStatOne failure code=0x%x",
360                       code);
361         }
362         cm_BPlusDirFreeEnumeration(enump);
363     }
364
365     return code;
366 }
367
368
369 #define RDR_POP_FOLLOW_MOUNTPOINTS 0x01
370 #define RDR_POP_EVALUATE_SYMLINKS  0x02
371 #define RDR_POP_WOW64              0x04
372 #define RDR_POP_NO_GETSTATUS       0x08
373
374 static afs_uint32
375 RDR_PopulateCurrentEntry( IN  AFSDirEnumEntry * pCurrentEntry,
376                           IN  DWORD             dwMaxEntryLength,
377                           IN  cm_scache_t     * dscp,
378                           IN  cm_scache_t     * scp,
379                           IN  cm_user_t       * userp,
380                           IN  cm_req_t        * reqp,
381                           IN  wchar_t         * name,
382                           IN  wchar_t         * shortName,
383                           IN  DWORD             dwFlags,
384                           IN  afs_uint32        cmError,
385                           OUT AFSDirEnumEntry **ppNextEntry,
386                           OUT DWORD           * pdwRemainingLength)
387 {
388     FILETIME ft;
389     WCHAR *  wname, *wtarget;
390     size_t   len;
391     DWORD      dwEntryLength;
392     afs_uint32 code = 0, code2 = 0;
393     BOOL          bMustFake = FALSE;
394
395     osi_Log5(afsd_logp, "RDR_PopulateCurrentEntry dscp=0x%p scp=0x%p name=%S short=%S flags=0x%x",
396              dscp, scp, osi_LogSaveStringW(afsd_logp, name),
397              osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
398     osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
399
400     if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
401         if (ppNextEntry)
402             *ppNextEntry = pCurrentEntry;
403         if (pdwRemainingLength)
404             *pdwRemainingLength = dwMaxEntryLength;
405         osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry Not Enough Room for Entry %d < %d",
406                  dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
407         return CM_ERROR_TOOBIG;
408     }
409
410     if (!name)
411         name = L"";
412     if (!shortName)
413         shortName = L"";
414
415     dwEntryLength = sizeof(AFSDirEnumEntry);
416
417     lock_ObtainWrite(&scp->rw);
418     if (dwFlags & RDR_POP_NO_GETSTATUS) {
419         if (!cm_HaveCallback(scp))
420             bMustFake = TRUE;
421     } else {
422 #ifdef AFS_FREELANCE_CLIENT
423         if (scp->fid.cell == AFS_FAKE_ROOT_CELL_ID && scp->fid.volume == AFS_FAKE_ROOT_VOL_ID) {
424             /*
425              * If the FID is from the Freelance Local Root always perform
426              * a single item status check.
427              */
428             code = cm_SyncOp( scp, NULL, userp, reqp, 0,
429                               CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
430             if (code) {
431                 lock_ReleaseWrite(&scp->rw);
432                 osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_SyncOp failed for scp=0x%p code=0x%x",
433                          scp, code);
434                 return code;
435             }
436         } else
437 #endif
438         {
439             /*
440              * For non-Freelance objects, check to see if we have current
441              * status information.  If not, perform a bulk status lookup of multiple
442              * entries in order to reduce the number of RPCs issued to the file server.
443              */
444             if (cm_EAccesFindEntry(userp, &scp->fid))
445                 bMustFake = TRUE;
446             else if (!cm_HaveCallback(scp)) {
447                 lock_ReleaseWrite(&scp->rw);
448                 code = RDR_BulkStatLookup(dscp, scp, userp, reqp);
449                 if (code) {
450                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry RDR_BulkStatLookup failed for scp=0x%p code=0x%x",
451                              scp, code);
452                     return code;
453                 }
454                 lock_ObtainWrite(&scp->rw);
455                 /*
456                  * RDR_BulkStatLookup can succeed but it may be the case that there
457                  * still is not valid status info.  If we get this far, generate fake
458                  * status info.
459                  */
460                 if (!cm_HaveCallback(scp))
461                     bMustFake = TRUE;
462             }
463         }
464     }
465
466     /* Populate the error code */
467     smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
468
469     /* Populate the real or fake data */
470     pCurrentEntry->FileId.Cell = scp->fid.cell;
471     pCurrentEntry->FileId.Volume = scp->fid.volume;
472     pCurrentEntry->FileId.Vnode = scp->fid.vnode;
473     pCurrentEntry->FileId.Unique = scp->fid.unique;
474     pCurrentEntry->FileId.Hash = scp->fid.hash;
475
476     pCurrentEntry->FileType = scp->fileType;
477
478     pCurrentEntry->DataVersion.QuadPart = scp->dataVersion;
479
480     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
481         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {
482         cm_LargeSearchTimeFromUnixTime(&ft, MAX_AFS_UINT32);
483     } else {
484         cm_LargeSearchTimeFromUnixTime(&ft, scp->cbExpires);
485     }
486     pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
487     pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
488
489     if (bMustFake) {
490         /* 1969-12-31 23:59:59 +00 */
491         ft.dwHighDateTime = 0x19DB200;
492         ft.dwLowDateTime = 0x5BB78980;
493     } else
494         cm_LargeSearchTimeFromUnixTime(&ft, scp->clientModTime);
495     pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
496     pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
497     pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
498     pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
499     pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
500
501     pCurrentEntry->EndOfFile = scp->length;
502     pCurrentEntry->AllocationSize = scp->length;
503
504     if (bMustFake) {
505         switch (scp->fileType) {
506         case CM_SCACHETYPE_DIRECTORY:
507             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
508             break;
509         case CM_SCACHETYPE_MOUNTPOINT:
510         case CM_SCACHETYPE_INVALID:
511             pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
512             break;
513         case CM_SCACHETYPE_SYMLINK:
514             if (cm_TargetPerceivedAsDirectory(scp->mountPointStringp))
515                 pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY | SMB_ATTR_REPARSE_POINT;
516             else
517                 pCurrentEntry->FileAttributes = SMB_ATTR_REPARSE_POINT;
518             break;
519         default:
520             /* if we get here we either have a normal file
521             * or we have a file for which we have never
522             * received status info.  In this case, we can
523             * check the even/odd value of the entry's vnode.
524             * odd means it is to be treated as a directory
525             * and even means it is to be treated as a file.
526             */
527             if (scp->fid.vnode & 0x1)
528                 pCurrentEntry->FileAttributes = SMB_ATTR_DIRECTORY;
529             else
530                 pCurrentEntry->FileAttributes = SMB_ATTR_NORMAL;
531         }
532     } else
533         pCurrentEntry->FileAttributes = smb_ExtAttributes(scp);
534     pCurrentEntry->EaSize = 0;
535     pCurrentEntry->Links = scp->linkCount;
536
537     len = wcslen(shortName);
538     wcsncpy(pCurrentEntry->ShortName, shortName, len);
539     pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
540
541     pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
542     len = wcslen(name);
543     wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
544     wcsncpy(wname, name, len);
545     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
546
547     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry scp=0x%p fileType=%d dv=%u",
548               scp, scp->fileType, (afs_uint32)scp->dataVersion);
549
550     if (!(dwFlags & RDR_POP_NO_GETSTATUS))
551         cm_SyncOpDone( scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
552
553     if ((dwFlags & RDR_POP_NO_GETSTATUS) || !cm_HaveCallback(scp)) {
554         pCurrentEntry->TargetNameOffset = 0;
555         pCurrentEntry->TargetNameLength = 0;
556     }
557     else
558     switch (scp->fileType) {
559     case CM_SCACHETYPE_MOUNTPOINT:
560         if (dwFlags & RDR_POP_FOLLOW_MOUNTPOINTS) {
561             if ((code2 = cm_ReadMountPoint(scp, userp, reqp)) == 0) {
562                 cm_scache_t *targetScp = NULL;
563
564                 pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
565                 len = strlen(scp->mountPointStringp);
566                 wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
567
568 #ifdef UNICODE
569                 cch = MultiByteToWideChar( CP_UTF8, 0, scp->mountPointStringp,
570                                            len * sizeof(char),
571                                            wtarget,
572                                            len * sizeof(WCHAR));
573 #else
574                 mbstowcs(wtarget, scp->mountPointStringp, len);
575 #endif
576                 pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
577
578                 code2 = cm_FollowMountPoint(scp, dscp, userp, reqp, &targetScp);
579
580                 if (code2 == 0) {
581                     pCurrentEntry->TargetFileId.Cell = targetScp->fid.cell;
582                     pCurrentEntry->TargetFileId.Volume = targetScp->fid.volume;
583                     pCurrentEntry->TargetFileId.Vnode = targetScp->fid.vnode;
584                     pCurrentEntry->TargetFileId.Unique = targetScp->fid.unique;
585                     pCurrentEntry->TargetFileId.Hash = targetScp->fid.hash;
586
587                     osi_Log4(afsd_logp, "RDR_PopulateCurrentEntry target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
588                               pCurrentEntry->TargetFileId.Cell, pCurrentEntry->TargetFileId.Volume,
589                               pCurrentEntry->TargetFileId.Vnode, pCurrentEntry->TargetFileId.Unique);
590
591                     cm_ReleaseSCache(targetScp);
592                 } else {
593                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_FollowMountPoint failed scp=0x%p code=0x%x",
594                               scp, code2);
595                 }
596             } else {
597                 osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_ReadMountPoint failed scp=0x%p code=0x%x",
598                           scp, code2);
599             }
600         }
601         break;
602     case CM_SCACHETYPE_SYMLINK:
603     case CM_SCACHETYPE_DFSLINK:
604         {
605             pCurrentEntry->TargetNameOffset = pCurrentEntry->FileNameOffset + pCurrentEntry->FileNameLength;
606             wtarget = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->TargetNameOffset);
607
608             if (dwFlags & RDR_POP_EVALUATE_SYMLINKS) {
609                 char * mp;
610
611                 code2 = cm_HandleLink(scp, userp, reqp);
612                 if (code2 == 0) {
613                     mp = scp->mountPointStringp;
614                     len = strlen(mp);
615                     if ( len != 0 ) {
616                         /* Strip off the msdfs: prefix from the target name for the file system */
617                         if (scp->fileType == CM_SCACHETYPE_DFSLINK) {
618                             osi_Log0(afsd_logp, "RDR_PopulateCurrentEntry DFSLink Detected");
619                             pCurrentEntry->FileType = scp->fileType;
620
621                             if (!strncmp("msdfs:", mp, 6)) {
622                                 mp += 6;
623                                 len -= 6;
624                             }
625                         }
626                         /* only send one slash to the redirector */
627                         if (mp[0] == '\\' && mp[1] == '\\') {
628                             mp++;
629                             len--;
630                         }
631 #ifdef UNICODE
632                         cch = MultiByteToWideChar( CP_UTF8, 0, mp,
633                                                    len * sizeof(char),
634                                                    wtarget,
635                                                    len * sizeof(WCHAR));
636 #else
637                         mbstowcs(wtarget, mp, len);
638 #endif
639                     }
640                     pCurrentEntry->TargetNameLength = (ULONG)(sizeof(WCHAR) * len);
641                 } else {
642                     osi_Log2(afsd_logp, "RDR_PopulateCurrentEntry cm_HandleLink failed scp=0x%p code=0x%x",
643                              scp, code2);
644                 }
645             }
646
647         }
648         break;
649
650     default:
651         pCurrentEntry->TargetNameOffset = 0;
652         pCurrentEntry->TargetNameLength = 0;
653     }
654     lock_ReleaseWrite(&scp->rw);
655
656     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
657     dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
658     if (ppNextEntry)
659         *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
660     if (pdwRemainingLength)
661         *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
662
663     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntry Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
664               pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
665
666     return code;
667 }
668
669 static afs_uint32
670 RDR_PopulateCurrentEntryNoScp( IN  AFSDirEnumEntry * pCurrentEntry,
671                                IN  DWORD             dwMaxEntryLength,
672                                IN  cm_scache_t     * dscp,
673                                IN  cm_fid_t        * fidp,
674                                IN  cm_user_t       * userp,
675                                IN  cm_req_t        * reqp,
676                                IN  wchar_t         * name,
677                                IN  wchar_t         * shortName,
678                                IN  DWORD             dwFlags,
679                                IN  afs_uint32        cmError,
680                                OUT AFSDirEnumEntry **ppNextEntry,
681                                OUT DWORD           * pdwRemainingLength)
682 {
683     FILETIME ft;
684     WCHAR *  wname;
685     size_t   len;
686     DWORD      dwEntryLength;
687     afs_uint32 code = 0, code2 = 0;
688
689     osi_Log4(afsd_logp, "RDR_PopulateCurrentEntryNoEntry dscp=0x%p name=%S short=%S flags=0x%x",
690              dscp, osi_LogSaveStringW(afsd_logp, name),
691              osi_LogSaveStringW(afsd_logp, shortName), dwFlags);
692     osi_Log1(afsd_logp, "... maxLength=%d", dwMaxEntryLength);
693
694     if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
695         if (ppNextEntry)
696             *ppNextEntry = pCurrentEntry;
697         if (pdwRemainingLength)
698             *pdwRemainingLength = dwMaxEntryLength;
699         osi_Log2(afsd_logp, "RDR_PopulateCurrentEntryNoEntry Not Enough Room for Entry %d < %d",
700                  dwMaxEntryLength, sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t));
701         return CM_ERROR_TOOBIG;
702     }
703
704     if (!name)
705         name = L"";
706     if (!shortName)
707         shortName = L"";
708
709     dwEntryLength = sizeof(AFSDirEnumEntry);
710
711     /* Populate the error code */
712     smb_MapNTError(cmError, &pCurrentEntry->NTStatus, TRUE);
713
714     /* Populate the fake data */
715     pCurrentEntry->FileId.Cell = fidp->cell;
716     pCurrentEntry->FileId.Volume = fidp->volume;
717     pCurrentEntry->FileId.Vnode = fidp->vnode;
718     pCurrentEntry->FileId.Unique = fidp->unique;
719     pCurrentEntry->FileId.Hash = fidp->hash;
720
721     pCurrentEntry->FileType = CM_SCACHETYPE_UNKNOWN;
722
723     pCurrentEntry->DataVersion.QuadPart = CM_SCACHE_VERSION_BAD;
724
725     cm_LargeSearchTimeFromUnixTime(&ft, 0);
726     pCurrentEntry->Expiration.LowPart = ft.dwLowDateTime;
727     pCurrentEntry->Expiration.HighPart = ft.dwHighDateTime;
728
729     cm_LargeSearchTimeFromUnixTime(&ft, 0);
730     pCurrentEntry->CreationTime.LowPart = ft.dwLowDateTime;
731     pCurrentEntry->CreationTime.HighPart = ft.dwHighDateTime;
732     pCurrentEntry->LastAccessTime = pCurrentEntry->CreationTime;
733     pCurrentEntry->LastWriteTime = pCurrentEntry->CreationTime;
734     pCurrentEntry->ChangeTime = pCurrentEntry->CreationTime;
735
736     pCurrentEntry->EndOfFile.QuadPart = 0;
737     pCurrentEntry->AllocationSize.QuadPart = 0;
738     pCurrentEntry->FileAttributes = 0;
739     pCurrentEntry->EaSize = 0;
740     pCurrentEntry->Links = 0;
741
742     len = wcslen(shortName);
743     wcsncpy(pCurrentEntry->ShortName, shortName, len);
744     pCurrentEntry->ShortNameLength = (CCHAR)(len * sizeof(WCHAR));
745
746     pCurrentEntry->FileNameOffset = sizeof(AFSDirEnumEntry);
747     len = wcslen(name);
748     wname = (WCHAR *)((PBYTE)pCurrentEntry + pCurrentEntry->FileNameOffset);
749     wcsncpy(wname, name, len);
750     pCurrentEntry->FileNameLength = (ULONG)(sizeof(WCHAR) * len);
751
752     pCurrentEntry->TargetNameOffset = 0;
753     pCurrentEntry->TargetNameLength = 0;
754
755     dwEntryLength += pCurrentEntry->FileNameLength + pCurrentEntry->TargetNameLength;
756     dwEntryLength += (dwEntryLength % 8) ? 8 - (dwEntryLength % 8) : 0;   /* quad align */
757     if (ppNextEntry)
758         *ppNextEntry = (AFSDirEnumEntry *)((PBYTE)pCurrentEntry + dwEntryLength);
759     if (pdwRemainingLength)
760         *pdwRemainingLength = dwMaxEntryLength - dwEntryLength;
761
762     osi_Log3(afsd_logp, "RDR_PopulateCurrentEntryNoScp Success FileNameLength=%d TargetNameLength=%d RemainingLength=%d",
763               pCurrentEntry->FileNameLength, pCurrentEntry->TargetNameLength, *pdwRemainingLength);
764
765     return code;
766 }
767
768 void
769 RDR_EnumerateDirectory( IN cm_user_t *userp,
770                         IN AFSFileID DirID,
771                         IN AFSDirQueryCB *QueryCB,
772                         IN BOOL bWow64,
773                         IN BOOL bSkipStatus,
774                         IN DWORD ResultBufferLength,
775                         IN OUT AFSCommResult **ResultCB)
776 {
777     DWORD status;
778     cm_direnum_t *      enump = NULL;
779     AFSDirEnumResp  * pDirEnumResp;
780     AFSDirEnumEntry * pCurrentEntry;
781     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
782     DWORD             dwMaxEntryLength;
783     afs_uint32  code = 0;
784     cm_fid_t      fid;
785     cm_scache_t * dscp = NULL;
786     cm_req_t      req;
787
788     RDR_InitReq(&req, bWow64);
789
790     osi_Log4(afsd_logp, "RDR_EnumerateDirectory FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
791              DirID.Cell, DirID.Volume, DirID.Vnode, DirID.Unique);
792
793     *ResultCB = (AFSCommResult *)malloc(size);
794     if (!(*ResultCB)) {
795         osi_Log0(afsd_logp, "RDR_EnumerateDirectory Out of Memory");
796         return;
797     }
798
799     memset(*ResultCB, 0, size);
800
801     if (QueryCB->EnumHandle == (ULONG_PTR)-1) {
802         osi_Log0(afsd_logp, "RDR_EnumerateDirectory No More Entries");
803         (*ResultCB)->ResultStatus = STATUS_NO_MORE_ENTRIES;
804         (*ResultCB)->ResultBufferLength = 0;
805         return;
806     }
807
808     (*ResultCB)->ResultBufferLength = dwMaxEntryLength = ResultBufferLength;
809     if (ResultBufferLength) {
810         pDirEnumResp = (AFSDirEnumResp *)&(*ResultCB)->ResultData;
811         pCurrentEntry = (AFSDirEnumEntry *)&pDirEnumResp->Entry;
812         dwMaxEntryLength -= FIELD_OFFSET( AFSDirEnumResp, Entry);      /* AFSDirEnumResp */
813     }
814
815     if (DirID.Cell != 0) {
816         fid.cell   = DirID.Cell;
817         fid.volume = DirID.Volume;
818         fid.vnode  = DirID.Vnode;
819         fid.unique = DirID.Unique;
820         fid.hash   = DirID.Hash;
821
822         code = cm_GetSCache(&fid, NULL, &dscp, userp, &req);
823         if (code) {
824             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
825             (*ResultCB)->ResultStatus = status;
826             osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure code=0x%x status=0x%x",
827                       code, status);
828             return;
829         }
830     } else {
831         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
832         osi_Log0(afsd_logp, "RDR_EnumerateDirectory Object Name Invalid - Cell = 0");
833         return;
834     }
835
836     /* get the directory size */
837     lock_ObtainWrite(&dscp->rw);
838     code = cm_SyncOp(dscp, NULL, userp, &req, PRSFS_LOOKUP,
839                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
840     if (code) {
841         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
842         (*ResultCB)->ResultStatus = status;
843         lock_ReleaseWrite(&dscp->rw);
844         cm_ReleaseSCache(dscp);
845         osi_Log2(afsd_logp, "RDR_EnumerateDirectory cm_SyncOp failure code=0x%x status=0x%x",
846                   code, status);
847         return;
848     }
849
850     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
851     lock_ReleaseWrite(&dscp->rw);
852
853     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
854         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
855         cm_ReleaseSCache(dscp);
856         osi_Log1(afsd_logp, "RDR_EnumerateDirectory Not a Directory dscp=0x%p",
857                  dscp);
858         return;
859     }
860
861     osi_Log1(afsd_logp, "RDR_EnumerateDirectory dv=%u", (afs_uint32)dscp->dataVersion);
862
863     /*
864      * If there is no enumeration handle, then this is a new query
865      * and we must perform an enumeration for the specified object.
866      */
867     if (QueryCB->EnumHandle == (ULONG_PTR)NULL) {
868         cm_dirOp_t    dirop;
869
870         code = cm_BeginDirOp(dscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
871         if (code == 0) {
872             code = cm_BPlusDirEnumerate(dscp, userp, &req,
873                                         TRUE /* dir locked */, NULL /* no mask */,
874                                         TRUE /* fetch status? */, &enump);
875             if (code) {
876                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumerate failure code=0x%x",
877                           code);
878             }
879             cm_EndDirOp(&dirop);
880         } else {
881             osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BeginDirOp failure code=0x%x",
882                       code);
883         }
884     } else {
885         enump = (cm_direnum_t *)QueryCB->EnumHandle;
886     }
887
888     if (enump) {
889         if (ResultBufferLength == 0) {
890             code = cm_BPlusDirEnumBulkStat(enump);
891             if (code) {
892                 osi_Log1(afsd_logp, "RDR_EnumerateDirectory cm_BPlusDirEnumBulkStat failure code=0x%x",
893                           code);
894             }
895         } else {
896             cm_direnum_entry_t * entryp = NULL;
897
898             pDirEnumResp->SnapshotDataVersion.QuadPart = enump->dataVersion;
899
900           getnextentry:
901             if (dwMaxEntryLength < sizeof(AFSDirEnumEntry) + (MAX_PATH + MOUNTPOINTLEN) * sizeof(wchar_t)) {
902                 osi_Log0(afsd_logp, "RDR_EnumerateDirectory out of space, returning");
903                 goto outofspace;
904             }
905
906             code = cm_BPlusDirNextEnumEntry(enump, &entryp);
907
908             if ((code == 0 || code == CM_ERROR_STOPNOW) && entryp) {
909                 cm_scache_t *scp = NULL;
910                 int stopnow = (code == CM_ERROR_STOPNOW);
911
912                 if ( !wcscmp(L".", entryp->name) || !wcscmp(L"..", entryp->name) ) {
913                     osi_Log0(afsd_logp, "RDR_EnumerateDirectory skipping . or ..");
914                     if (stopnow)
915                         goto outofspace;
916                     goto getnextentry;
917                 }
918
919                 if (bSkipStatus) {
920                     code = cm_GetSCache(&entryp->fid, &dscp->fid, &scp, userp, &req);
921                     if (code) {
922                         osi_Log5(afsd_logp, "RDR_EnumerateDirectory cm_GetSCache failure cell %u vol %u vnode %u uniq %u code=0x%x",
923                                  entryp->fid.cell, entryp->fid.volume, entryp->fid.vnode, entryp->fid.unique, code);
924                     }
925                 } else {
926                     code = entryp->errorCode;
927                     scp = code ? NULL : cm_FindSCache(&entryp->fid);
928                 }
929
930                 if (scp) {
931                     code = RDR_PopulateCurrentEntry( pCurrentEntry, dwMaxEntryLength,
932                                                      dscp, scp, userp, &req,
933                                                      entryp->name,
934                                                      cm_shortNames && cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
935                                                      (bWow64 ? RDR_POP_WOW64 : 0) |
936                                                      (bSkipStatus ? RDR_POP_NO_GETSTATUS : 0),
937                                                      code,
938                                                      &pCurrentEntry, &dwMaxEntryLength);
939                     cm_ReleaseSCache(scp);
940                 } else {
941                     code = RDR_PopulateCurrentEntryNoScp( pCurrentEntry, dwMaxEntryLength,
942                                                           dscp, &entryp->fid, userp, &req,
943                                                           entryp->name,
944                                                           cm_shortNames && cm_Is8Dot3(entryp->name) ? NULL : entryp->shortName,
945                                                           (bWow64 ? RDR_POP_WOW64 : 0),
946                                                           code,
947                                                           &pCurrentEntry, &dwMaxEntryLength);
948                 }
949                 if (stopnow)
950                     goto outofspace;
951                 goto getnextentry;
952             }
953         }
954     }
955
956   outofspace:
957
958     if (code || enump->next == enump->count || ResultBufferLength == 0) {
959         cm_BPlusDirFreeEnumeration(enump);
960         enump = (cm_direnum_t *)(ULONG_PTR)-1;
961     }
962
963     if (code == 0 || code == CM_ERROR_STOPNOW) {
964         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
965         osi_Log0(afsd_logp, "RDR_EnumerateDirectory SUCCESS");
966     } else {
967         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
968         (*ResultCB)->ResultStatus = status;
969         osi_Log2(afsd_logp, "RDR_EnumerateDirectory Failure code=0x%x status=0x%x",
970                   code, status);
971     }
972
973     if (ResultBufferLength) {
974         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwMaxEntryLength;
975
976         pDirEnumResp->EnumHandle = (ULONG_PTR) enump;
977         pDirEnumResp->CurrentDataVersion.QuadPart = dscp->dataVersion;
978     }
979
980     if (dscp)
981         cm_ReleaseSCache(dscp);
982
983     return;
984 }
985
986 void
987 RDR_EvaluateNodeByName( IN cm_user_t *userp,
988                         IN AFSFileID ParentID,
989                         IN WCHAR   *FileNameCounted,
990                         IN DWORD    FileNameLength,
991                         IN BOOL     CaseSensitive,
992                         IN BOOL     LastComponent,
993                         IN BOOL     bWow64,
994                         IN BOOL     bHoldFid,
995                         IN BOOL     bNoFollow,
996                         IN DWORD    ResultBufferLength,
997                         IN OUT AFSCommResult **ResultCB)
998 {
999     AFSFileEvalResultCB *pEvalResultCB = NULL;
1000     AFSDirEnumEntry * pCurrentEntry;
1001     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
1002     afs_uint32  code = 0;
1003     cm_scache_t * scp = NULL;
1004     cm_scache_t * dscp = NULL;
1005     cm_req_t      req;
1006     cm_fid_t      parentFid;
1007     DWORD         status;
1008     DWORD         dwRemaining;
1009     WCHAR       * wszName = NULL;
1010     size_t        cbName;
1011     BOOL          bVol = FALSE;
1012     wchar_t       FileName[260];
1013     afs_uint32    lookupFlags;
1014
1015     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
1016
1017     RDR_InitReq(&req, bWow64);
1018
1019     osi_Log4(afsd_logp, "RDR_EvaluateNodeByName parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1020              ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1021
1022     /* Allocate enough room to add a volume prefix if necessary */
1023     cbName = FileNameLength + (CM_PREFIX_VOL_CCH + 64) * sizeof(WCHAR);
1024     wszName = malloc(cbName);
1025     if (!wszName) {
1026         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
1027         return;
1028     }
1029     StringCbCopyNW(wszName, cbName, FileName, FileNameLength);
1030     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, wszName));
1031
1032     *ResultCB = (AFSCommResult *)malloc(size);
1033     if (!(*ResultCB)) {
1034         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Out of Memory");
1035         free(wszName);
1036         return;
1037     }
1038
1039     memset(*ResultCB, 0, size);
1040     (*ResultCB)->ResultBufferLength = 0;
1041     dwRemaining = ResultBufferLength;
1042     if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
1043         pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
1044         pCurrentEntry = &pEvalResultCB->DirEnum;
1045         dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
1046     }
1047
1048     if (ParentID.Cell != 0) {
1049         parentFid.cell   = ParentID.Cell;
1050         parentFid.volume = ParentID.Volume;
1051         parentFid.vnode  = ParentID.Vnode;
1052         parentFid.unique = ParentID.Unique;
1053         parentFid.hash   = ParentID.Hash;
1054
1055         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1056         if (code) {
1057             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1058             (*ResultCB)->ResultStatus = status;
1059             if ( status == STATUS_INVALID_HANDLE)
1060                 status = STATUS_OBJECT_PATH_INVALID;
1061             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName cm_GetSCache parentFID failure code=0x%x status=0x%x",
1062                       code, status);
1063             free(wszName);
1064             return;
1065         }
1066     } else {
1067         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
1068         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName Object Name Invalid - Cell = 0");
1069         return;
1070     }
1071
1072     /* get the directory size */
1073     lock_ObtainWrite(&dscp->rw);
1074     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1075                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1076     if (code) {
1077         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1078         (*ResultCB)->ResultStatus = status;
1079         lock_ReleaseWrite(&dscp->rw);
1080         cm_ReleaseSCache(dscp);
1081         osi_Log3(afsd_logp, "RDR_EvaluateNodeByName cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1082                  dscp, code, status);
1083         free(wszName);
1084         return;
1085     }
1086     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1087     lock_ReleaseWrite(&dscp->rw);
1088
1089     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1090         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1091         cm_ReleaseSCache(dscp);
1092         osi_Log1(afsd_logp, "RDR_EvaluateNodeByName Not a Directory dscp=0x%p",
1093                  dscp);
1094         free(wszName);
1095         return;
1096     }
1097
1098     lookupFlags = CM_FLAG_NOMOUNTCHASE;
1099
1100     if ( !LastComponent )
1101         lookupFlags |= CM_FLAG_CHECKPATH;
1102     code = cm_Lookup(dscp, wszName, lookupFlags, userp, &req, &scp);
1103
1104     if (!CaseSensitive &&
1105         (code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH)) {
1106         lookupFlags |= CM_FLAG_CASEFOLD;
1107         code = cm_Lookup(dscp, wszName, lookupFlags, userp, &req, &scp);
1108     }
1109
1110     if ((code == CM_ERROR_NOSUCHPATH || code == CM_ERROR_NOSUCHFILE || code == CM_ERROR_BPLUS_NOMATCH) &&
1111          dscp == cm_data.rootSCachep) {
1112
1113         if (wcschr(wszName, '%') != NULL || wcschr(wszName, '#') != NULL) {
1114             /*
1115              * A volume reference:  <cell>{%,#}<volume> -> @vol:<cell>{%,#}<volume>
1116              */
1117             StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
1118             StringCbCatNW(wszName, cbName, FileName, FileNameLength);
1119             bVol = TRUE;
1120
1121             code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
1122         }
1123 #ifdef AFS_FREELANCE_CLIENT
1124         else if (dscp->fid.cell == AFS_FAKE_ROOT_CELL_ID && dscp->fid.volume == AFS_FAKE_ROOT_VOL_ID &&
1125                  dscp->fid.vnode == 1 && dscp->fid.unique == 1) {
1126             /*
1127              * If this is the Freelance volume root directory then treat unrecognized
1128              * names as cell names and attempt to find the appropriate "root.cell".
1129              */
1130             StringCchCopyNW(wszName, cbName, _C(CM_PREFIX_VOL), CM_PREFIX_VOL_CCH);
1131             if (FileName[0] == L'.') {
1132                 StringCbCatNW(wszName, cbName, &FileName[1], FileNameLength);
1133                 StringCbCatNW(wszName, cbName, L"%", sizeof(WCHAR));
1134             } else {
1135                 StringCbCatNW(wszName, cbName, FileName, FileNameLength);
1136                 StringCbCatNW(wszName, cbName, L"#", sizeof(WCHAR));
1137             }
1138             StringCbCatNW(wszName, cbName, L"root.cell", 9 * sizeof(WCHAR));
1139             bVol = TRUE;
1140
1141             code = cm_EvaluateVolumeReference(wszName, CM_FLAG_CHECKPATH, userp, &req, &scp);
1142         }
1143 #endif
1144     }
1145
1146     if (code == 0 && scp) {
1147         wchar_t shortName[13]=L"";
1148
1149         if (!cm_shortNames) {
1150             shortName[0] = L'\0';
1151         } else if (bVol) {
1152             cm_Gen8Dot3VolNameW(scp->fid.cell, scp->fid.volume, shortName, NULL);
1153         } else if (!cm_Is8Dot3(wszName)) {
1154             cm_dirFid_t dfid;
1155
1156             dfid.vnode = htonl(scp->fid.vnode);
1157             dfid.unique = htonl(scp->fid.unique);
1158
1159             cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
1160         } else {
1161             shortName[0] = L'\0';
1162         }
1163
1164         code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
1165                                         dscp, scp, userp, &req,
1166                                         FileName, shortName,
1167                                         (bWow64 ? RDR_POP_WOW64 : 0) |
1168                                         (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
1169                                         0, NULL, &dwRemaining);
1170         if (bHoldFid)
1171             RDR_FlagScpInUse( scp, FALSE );
1172         cm_ReleaseSCache(scp);
1173
1174         if (code) {
1175             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1176             (*ResultCB)->ResultStatus = status;
1177             osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
1178                       code, status);
1179         } else {
1180             pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1181             (*ResultCB)->ResultStatus = STATUS_SUCCESS;
1182             (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1183             osi_Log0(afsd_logp, "RDR_EvaluateNodeByName SUCCESS");
1184         }
1185     } else if (code) {
1186         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1187         (*ResultCB)->ResultStatus = status;
1188         osi_Log2(afsd_logp, "RDR_EvaluateNodeByName FAILURE code=0x%x status=0x%x",
1189                  code, status);
1190     } else {
1191         (*ResultCB)->ResultStatus = STATUS_NO_SUCH_FILE;
1192         osi_Log0(afsd_logp, "RDR_EvaluateNodeByName No Such File");
1193     }
1194     cm_ReleaseSCache(dscp);
1195     free(wszName);
1196
1197     return;
1198 }
1199
1200 void
1201 RDR_EvaluateNodeByID( IN cm_user_t *userp,
1202                       IN AFSFileID ParentID,            /* not used */
1203                       IN AFSFileID SourceID,
1204                       IN BOOL      bWow64,
1205                       IN BOOL      bNoFollow,
1206                       IN BOOL      bHoldFid,
1207                       IN DWORD     ResultBufferLength,
1208                       IN OUT AFSCommResult **ResultCB)
1209 {
1210     AFSFileEvalResultCB *pEvalResultCB = NULL;
1211     AFSDirEnumEntry * pCurrentEntry = NULL;
1212     size_t size = ResultBufferLength ? sizeof(AFSCommResult) + ResultBufferLength - 1 : sizeof(AFSCommResult);
1213     afs_uint32  code = 0;
1214     cm_scache_t * scp = NULL;
1215     cm_scache_t * dscp = NULL;
1216     cm_req_t      req;
1217     cm_fid_t      Fid;
1218     cm_fid_t      parentFid;
1219     DWORD         status;
1220     DWORD         dwRemaining;
1221
1222     osi_Log4(afsd_logp, "RDR_EvaluateNodeByID source FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1223               SourceID.Cell, SourceID.Volume, SourceID.Vnode, SourceID.Unique);
1224     osi_Log4(afsd_logp, "... parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1225               ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1226
1227     *ResultCB = (AFSCommResult *)malloc(size);
1228     if (!(*ResultCB)) {
1229         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Out of Memory");
1230         return;
1231     }
1232
1233     memset(*ResultCB, 0, size);
1234     (*ResultCB)->ResultBufferLength = 0;
1235     dwRemaining = ResultBufferLength;
1236     if (ResultBufferLength >= sizeof( AFSFileEvalResultCB)) {
1237         pEvalResultCB = (AFSFileEvalResultCB *)&(*ResultCB)->ResultData;
1238         pCurrentEntry = &pEvalResultCB->DirEnum;
1239         dwRemaining -= (sizeof( AFSFileEvalResultCB) - sizeof( AFSDirEnumEntry));
1240     }
1241
1242     RDR_InitReq(&req, bWow64);
1243
1244     if (SourceID.Cell != 0) {
1245         cm_SetFid(&Fid, SourceID.Cell, SourceID.Volume, SourceID.Vnode, SourceID.Unique);
1246         code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
1247         if (code) {
1248             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1249             (*ResultCB)->ResultStatus = status;
1250             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache SourceFID failure code=0x%x status=0x%x",
1251                       code, status);
1252             return;
1253         }
1254     } else {
1255         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
1256         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Name Invalid - Cell = 0");
1257         return;
1258     }
1259
1260     if (ParentID.Cell != 0) {
1261         cm_SetFid(&parentFid, ParentID.Cell, ParentID.Volume, ParentID.Vnode, ParentID.Unique);
1262         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1263         if (code) {
1264             cm_ReleaseSCache(scp);
1265             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1266             if ( status == STATUS_INVALID_HANDLE)
1267                 status = STATUS_OBJECT_PATH_INVALID;
1268             (*ResultCB)->ResultStatus = status;
1269             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
1270                       code, status);
1271             return;
1272         }
1273     } else if (SourceID.Vnode == 1) {
1274         dscp = scp;
1275         cm_HoldSCache(dscp);
1276     } else if (scp->parentVnode) {
1277         cm_SetFid(&parentFid, SourceID.Cell, SourceID.Volume, scp->parentVnode, scp->parentUnique);
1278         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1279         if (code) {
1280             cm_ReleaseSCache(scp);
1281             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1282             if ( status == STATUS_INVALID_HANDLE)
1283                 status = STATUS_OBJECT_PATH_INVALID;
1284             (*ResultCB)->ResultStatus = status;
1285             osi_Log2(afsd_logp, "RDR_EvaluateNodeByID cm_GetSCache parentFID failure code=0x%x status=0x%x",
1286                       code, status);
1287             return;
1288         }
1289     } else {
1290         (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
1291         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID Object Path Invalid - Unknown Parent");
1292         return;
1293     }
1294
1295     /* Make sure the directory is current */
1296     lock_ObtainWrite(&dscp->rw);
1297     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1298                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1299     if (code) {
1300         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1301         (*ResultCB)->ResultStatus = status;
1302         lock_ReleaseWrite(&dscp->rw);
1303         cm_ReleaseSCache(dscp);
1304         cm_ReleaseSCache(scp);
1305         osi_Log3(afsd_logp, "RDR_EvaluateNodeByID cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1306                  dscp, code, status);
1307         return;
1308     }
1309
1310     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1311     lock_ReleaseWrite(&dscp->rw);
1312
1313     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1314         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1315         cm_ReleaseSCache(dscp);
1316         cm_ReleaseSCache(scp);
1317         osi_Log1(afsd_logp, "RDR_EvaluateNodeByID Not a Directory dscp=0x%p", dscp);
1318         return;
1319     }
1320
1321     code = RDR_PopulateCurrentEntry(pCurrentEntry, dwRemaining,
1322                                     dscp, scp, userp, &req, NULL, NULL,
1323                                     (bWow64 ? RDR_POP_WOW64 : 0) |
1324                                     (bNoFollow ? 0 : (RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS)),
1325                                     0, NULL, &dwRemaining);
1326
1327     if (bHoldFid)
1328         RDR_FlagScpInUse( scp, FALSE );
1329     cm_ReleaseSCache(scp);
1330     cm_ReleaseSCache(dscp);
1331
1332     if (code) {
1333         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1334         (*ResultCB)->ResultStatus = status;
1335         osi_Log2(afsd_logp, "RDR_EvaluateNodeByID FAILURE code=0x%x status=0x%x",
1336                  code, status);
1337     } else {
1338         pEvalResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1339
1340         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
1341         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1342         osi_Log0(afsd_logp, "RDR_EvaluateNodeByID SUCCESS");
1343     }
1344     return;
1345 }
1346
1347 void
1348 RDR_CreateFileEntry( IN cm_user_t *userp,
1349                      IN WCHAR *FileNameCounted,
1350                      IN DWORD FileNameLength,
1351                      IN AFSFileCreateCB *CreateCB,
1352                      IN BOOL bWow64,
1353                      IN BOOL bHoldFid,
1354                      IN DWORD ResultBufferLength,
1355                      IN OUT AFSCommResult **ResultCB)
1356 {
1357     AFSFileCreateResultCB *pResultCB = NULL;
1358     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1359     cm_fid_t            parentFid;
1360     afs_uint32          code;
1361     cm_scache_t *       dscp = NULL;
1362     afs_uint32          flags = 0;
1363     cm_attr_t           setAttr;
1364     cm_scache_t *       scp = NULL;
1365     cm_req_t            req;
1366     DWORD               status;
1367     wchar_t             FileName[260];
1368
1369     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
1370
1371     osi_Log4(afsd_logp, "RDR_CreateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1372               CreateCB->ParentId.Cell, CreateCB->ParentId.Volume,
1373               CreateCB->ParentId.Vnode, CreateCB->ParentId.Unique);
1374     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
1375
1376     RDR_InitReq(&req, bWow64);
1377     memset(&setAttr, 0, sizeof(cm_attr_t));
1378
1379     *ResultCB = (AFSCommResult *)malloc(size);
1380     if (!(*ResultCB)) {
1381         osi_Log0(afsd_logp, "RDR_CreateFileEntry out of memory");
1382         return;
1383     }
1384
1385     memset( *ResultCB,
1386             '\0',
1387             size);
1388
1389     parentFid.cell   = CreateCB->ParentId.Cell;
1390     parentFid.volume = CreateCB->ParentId.Volume;
1391     parentFid.vnode  = CreateCB->ParentId.Vnode;
1392     parentFid.unique = CreateCB->ParentId.Unique;
1393     parentFid.hash   = CreateCB->ParentId.Hash;
1394
1395     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1396     if (code) {
1397         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1398         (*ResultCB)->ResultStatus = status;
1399         if ( status == STATUS_INVALID_HANDLE)
1400             status = STATUS_OBJECT_PATH_INVALID;
1401         osi_Log2(afsd_logp, "RDR_CreateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1402                   code, status);
1403         return;
1404     }
1405
1406     lock_ObtainWrite(&dscp->rw);
1407     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1408                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1409     if (code) {
1410         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1411         (*ResultCB)->ResultStatus = status;
1412         lock_ReleaseWrite(&dscp->rw);
1413         cm_ReleaseSCache(dscp);
1414         osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
1415                  dscp, code, status);
1416         return;
1417     }
1418
1419     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1420     lock_ReleaseWrite(&dscp->rw);
1421
1422     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1423         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1424         cm_ReleaseSCache(dscp);
1425         osi_Log1(afsd_logp, "RDR_CreateFileEntry Not a Directory dscp=0x%p",
1426                  dscp);
1427         return;
1428     }
1429
1430     /* Use current time */
1431     setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
1432     setAttr.clientModTime = time(NULL);
1433
1434     if (CreateCB->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1435         if (smb_unixModeDefaultDir) {
1436             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1437             setAttr.unixModeBits = smb_unixModeDefaultDir;
1438             if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
1439                 setAttr.unixModeBits &= ~0222;          /* disable the write bits */
1440         }
1441
1442         code = cm_MakeDir(dscp, FileName, flags, &setAttr, userp, &req, &scp);
1443     } else {
1444         if (smb_unixModeDefaultFile) {
1445             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1446             setAttr.unixModeBits = smb_unixModeDefaultFile;
1447             if (CreateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)
1448                 setAttr.unixModeBits &= ~0222;          /* disable the write bits */
1449         }
1450
1451         setAttr.mask |= CM_ATTRMASK_LENGTH;
1452         setAttr.length.LowPart = CreateCB->AllocationSize.LowPart;
1453         setAttr.length.HighPart = CreateCB->AllocationSize.HighPart;
1454         code = cm_Create(dscp, FileName, flags, &setAttr, &scp, userp, &req);
1455     }
1456     if (code == 0) {
1457         wchar_t shortName[13]=L"";
1458         cm_dirFid_t dfid;
1459         DWORD dwRemaining;
1460
1461         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
1462
1463         (*ResultCB)->ResultBufferLength = sizeof( AFSFileCreateResultCB);
1464
1465         pResultCB = (AFSFileCreateResultCB *)(*ResultCB)->ResultData;
1466
1467         dwRemaining = ResultBufferLength - sizeof( AFSFileCreateResultCB) + sizeof( AFSDirEnumEntry);
1468
1469         lock_ObtainWrite(&dscp->rw);
1470         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1471                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1472         if (code) {
1473             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1474             (*ResultCB)->ResultStatus = status;
1475             lock_ReleaseWrite(&dscp->rw);
1476             cm_ReleaseSCache(dscp);
1477             cm_ReleaseSCache(scp);
1478             osi_Log3(afsd_logp, "RDR_CreateFileEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
1479                       dscp, code, status);
1480             return;
1481         }
1482
1483         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1484
1485         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1486         lock_ReleaseWrite(&dscp->rw);
1487
1488         if (cm_shortNames) {
1489             dfid.vnode = htonl(scp->fid.vnode);
1490             dfid.unique = htonl(scp->fid.unique);
1491
1492             if (!cm_Is8Dot3(FileName))
1493                 cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
1494             else
1495                 shortName[0] = '\0';
1496         }
1497
1498         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
1499                                         dscp, scp, userp, &req, FileName, shortName,
1500                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
1501                                         0, NULL, &dwRemaining);
1502
1503         if (bHoldFid)
1504             RDR_FlagScpInUse( scp, FALSE );
1505         cm_ReleaseSCache(scp);
1506         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1507         osi_Log0(afsd_logp, "RDR_CreateFileEntry SUCCESS");
1508     } else {
1509         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1510         (*ResultCB)->ResultStatus = status;
1511         (*ResultCB)->ResultBufferLength = 0;
1512         osi_Log2(afsd_logp, "RDR_CreateFileEntry FAILURE code=0x%x status=0x%x",
1513                   code, status);
1514     }
1515
1516     cm_ReleaseSCache(dscp);
1517
1518     return;
1519 }
1520
1521 void
1522 RDR_UpdateFileEntry( IN cm_user_t *userp,
1523                      IN AFSFileID FileId,
1524                      IN AFSFileUpdateCB *UpdateCB,
1525                      IN BOOL bWow64,
1526                      IN DWORD ResultBufferLength,
1527                      IN OUT AFSCommResult **ResultCB)
1528 {
1529     AFSFileUpdateResultCB *pResultCB = NULL;
1530     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1531     cm_fid_t            Fid;
1532     cm_fid_t            parentFid;
1533     afs_uint32          code;
1534     afs_uint32          flags = 0;
1535     cm_attr_t           setAttr;
1536     cm_scache_t *       scp = NULL;
1537     cm_scache_t *       dscp = NULL;
1538     cm_req_t            req;
1539     time_t              clientModTime;
1540     FILETIME            ft;
1541     DWORD               status;
1542     BOOL                bScpLocked = FALSE;
1543
1544     RDR_InitReq(&req, bWow64);
1545     memset(&setAttr, 0, sizeof(cm_attr_t));
1546
1547     osi_Log4(afsd_logp, "RDR_UpdateFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1548               UpdateCB->ParentId.Cell, UpdateCB->ParentId.Volume,
1549               UpdateCB->ParentId.Vnode, UpdateCB->ParentId.Unique);
1550     osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1551               FileId.Cell, FileId.Volume,
1552               FileId.Vnode, FileId.Unique);
1553
1554     *ResultCB = (AFSCommResult *)malloc( size);
1555     if (!(*ResultCB)) {
1556         osi_Log0(afsd_logp, "RDR_UpdateFileEntry Out of Memory");
1557         return;
1558     }
1559
1560     memset( *ResultCB,
1561             '\0',
1562             size);
1563
1564     parentFid.cell   = UpdateCB->ParentId.Cell;
1565     parentFid.volume = UpdateCB->ParentId.Volume;
1566     parentFid.vnode  = UpdateCB->ParentId.Vnode;
1567     parentFid.unique = UpdateCB->ParentId.Unique;
1568     parentFid.hash   = UpdateCB->ParentId.Hash;
1569
1570     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1571     if (code) {
1572         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1573         (*ResultCB)->ResultStatus = status;
1574         if ( status == STATUS_INVALID_HANDLE)
1575             status = STATUS_OBJECT_PATH_INVALID;
1576         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1577                   code, status);
1578         return;
1579     }
1580
1581     lock_ObtainWrite(&dscp->rw);
1582     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1583                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1584     if (code) {
1585         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1586         (*ResultCB)->ResultStatus = status;
1587         lock_ReleaseWrite(&dscp->rw);
1588         cm_ReleaseSCache(dscp);
1589         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
1590                  dscp, code, status);
1591         return;
1592     }
1593
1594     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1595     lock_ReleaseWrite(&dscp->rw);
1596
1597     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1598         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1599         cm_ReleaseSCache(dscp);
1600         osi_Log1(afsd_logp, "RDR_UpdateFileEntry Not a Directory dscp=0x%p",
1601                  dscp);
1602         return;
1603     }
1604
1605     Fid.cell   = FileId.Cell;
1606     Fid.volume = FileId.Volume;
1607     Fid.vnode  = FileId.Vnode;
1608     Fid.unique = FileId.Unique;
1609     Fid.hash   = FileId.Hash;
1610
1611     code = cm_GetSCache(&Fid, &dscp->fid, &scp, userp, &req);
1612     if (code) {
1613         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1614         (*ResultCB)->ResultStatus = status;
1615         cm_ReleaseSCache(dscp);
1616         osi_Log2(afsd_logp, "RDR_UpdateFileEntry cm_GetSCache object FID failure code=0x%x status=0x%x",
1617                   code, status);
1618         return;
1619     }
1620
1621     lock_ObtainWrite(&scp->rw);
1622     bScpLocked = TRUE;
1623     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1624                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1625     if (code) {
1626         lock_ReleaseWrite(&scp->rw);
1627         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1628         (*ResultCB)->ResultStatus = status;
1629         (*ResultCB)->ResultBufferLength = 0;
1630         cm_ReleaseSCache(dscp);
1631         cm_ReleaseSCache(scp);
1632         osi_Log3(afsd_logp, "RDR_UpdateFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
1633                  scp, code, status);
1634         return;
1635     }
1636     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1637
1638     if (UpdateCB->ChangeTime.QuadPart) {
1639
1640         if (scp->fileType == CM_SCACHETYPE_FILE) {
1641             /* Do not set length and other attributes at the same time */
1642             if (scp->length.QuadPart != UpdateCB->AllocationSize.QuadPart) {
1643                 osi_Log2(afsd_logp, "RDR_UpdateFileEntry Length Change 0x%x -> 0x%x",
1644                           (afs_uint32)scp->length.QuadPart, (afs_uint32)UpdateCB->AllocationSize.QuadPart);
1645                 setAttr.mask |= CM_ATTRMASK_LENGTH;
1646                 setAttr.length.LowPart = UpdateCB->AllocationSize.LowPart;
1647                 setAttr.length.HighPart = UpdateCB->AllocationSize.HighPart;
1648                 lock_ReleaseWrite(&scp->rw);
1649                 bScpLocked = FALSE;
1650                 code = cm_SetAttr(scp, &setAttr, userp, &req);
1651                 if (code)
1652                     goto on_error;
1653                 setAttr.mask = 0;
1654             }
1655         }
1656
1657         if (!bScpLocked) {
1658             lock_ObtainWrite(&scp->rw);
1659             bScpLocked = TRUE;
1660         }
1661         if ((scp->unixModeBits & 0200) && (UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1662             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1663             setAttr.unixModeBits = scp->unixModeBits & ~0222;
1664         } else if (!(scp->unixModeBits & 0200) && !(UpdateCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1665             setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1666             setAttr.unixModeBits = scp->unixModeBits | 0222;
1667         }
1668     }
1669
1670     if (UpdateCB->LastWriteTime.QuadPart) {
1671         ft.dwLowDateTime = UpdateCB->LastWriteTime.LowPart;
1672         ft.dwHighDateTime = UpdateCB->LastWriteTime.HighPart;
1673
1674         cm_UnixTimeFromLargeSearchTime(& clientModTime, &ft);
1675
1676         if (!bScpLocked) {
1677             lock_ObtainWrite(&scp->rw);
1678             bScpLocked = TRUE;
1679         }
1680         if (scp->clientModTime != clientModTime) {
1681             setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1682             setAttr.clientModTime = clientModTime;
1683         }
1684
1685         /* call setattr */
1686         if (setAttr.mask) {
1687             lock_ReleaseWrite(&scp->rw);
1688             bScpLocked = FALSE;
1689             code = cm_SetAttr(scp, &setAttr, userp, &req);
1690         } else
1691             code = 0;
1692     }
1693
1694   on_error:
1695     if (bScpLocked) {
1696         lock_ReleaseWrite(&scp->rw);
1697     }
1698
1699     if (code == 0) {
1700         DWORD dwRemaining = ResultBufferLength - sizeof( AFSFileUpdateResultCB) + sizeof( AFSDirEnumEntry);
1701
1702         pResultCB = (AFSFileUpdateResultCB *)(*ResultCB)->ResultData;
1703
1704         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
1705
1706         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
1707                                         dscp, scp, userp, &req, NULL, NULL,
1708                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
1709                                         0, NULL, &dwRemaining);
1710         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
1711         osi_Log0(afsd_logp, "RDR_UpdateFileEntry SUCCESS");
1712     } else {
1713         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1714         (*ResultCB)->ResultStatus = status;
1715         (*ResultCB)->ResultBufferLength = 0;
1716         osi_Log2(afsd_logp, "RDR_UpdateFileEntry FAILURE code=0x%x status=0x%x",
1717                   code, status);
1718     }
1719     cm_ReleaseSCache(scp);
1720     cm_ReleaseSCache(dscp);
1721
1722     return;
1723 }
1724
1725 void
1726 RDR_CleanupFileEntry( IN cm_user_t *userp,
1727                       IN AFSFileID FileId,
1728                       IN WCHAR *FileNameCounted,
1729                       IN DWORD FileNameLength,
1730                       IN AFSFileCleanupCB *CleanupCB,
1731                       IN BOOL bWow64,
1732                       IN BOOL bLastHandle,
1733                       IN BOOL bDeleteFile,
1734                       IN BOOL bUnlockFile,
1735                       IN DWORD ResultBufferLength,
1736                       IN OUT AFSCommResult **ResultCB)
1737 {
1738     AFSFileCleanupResultCB *pResultCB = NULL;
1739     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
1740     cm_fid_t            Fid;
1741     cm_fid_t            parentFid;
1742     afs_uint32          code = 0;
1743     afs_uint32          flags = 0;
1744     cm_attr_t           setAttr;
1745     cm_scache_t *       scp = NULL;
1746     cm_scache_t *       dscp = NULL;
1747     cm_req_t            req;
1748     time_t              clientModTime;
1749     FILETIME            ft;
1750     DWORD               status;
1751     BOOL                bScpLocked = FALSE;
1752     BOOL                bDscpLocked = FALSE;
1753     BOOL                bFlushFile = FALSE;
1754     cm_key_t            key;
1755
1756     RDR_InitReq(&req, bWow64);
1757     memset(&setAttr, 0, sizeof(cm_attr_t));
1758
1759     osi_Log4(afsd_logp, "RDR_CleanupFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1760               CleanupCB->ParentId.Cell, CleanupCB->ParentId.Volume,
1761               CleanupCB->ParentId.Vnode, CleanupCB->ParentId.Unique);
1762     osi_Log4(afsd_logp, "... object FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
1763               FileId.Cell, FileId.Volume,
1764               FileId.Vnode, FileId.Unique);
1765
1766     *ResultCB = (AFSCommResult *)malloc( size);
1767     if (!(*ResultCB)) {
1768         osi_Log0(afsd_logp, "RDR_CleanupFileEntry Out of Memory");
1769         return;
1770     }
1771
1772     memset( *ResultCB,
1773             '\0',
1774             size);
1775
1776     parentFid.cell   = CleanupCB->ParentId.Cell;
1777     parentFid.volume = CleanupCB->ParentId.Volume;
1778     parentFid.vnode  = CleanupCB->ParentId.Vnode;
1779     parentFid.unique = CleanupCB->ParentId.Unique;
1780     parentFid.hash   = CleanupCB->ParentId.Hash;
1781
1782     if (parentFid.cell) {
1783         code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
1784         if (code) {
1785             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
1786             if ( status == STATUS_INVALID_HANDLE)
1787                 status = STATUS_OBJECT_PATH_INVALID;
1788             (*ResultCB)->ResultStatus = status;
1789             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
1790                      code, status);
1791             return;
1792         }
1793
1794         lock_ObtainWrite(&dscp->rw);
1795         bDscpLocked = TRUE;
1796         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
1797                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1798         if (code) {
1799             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure dscp=0x%p code=0x%x",
1800                     dscp, code);
1801             if (code)
1802                 goto on_error;
1803         }
1804
1805         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1806         lock_ReleaseWrite(&dscp->rw);
1807         bDscpLocked = FALSE;
1808
1809         if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
1810             (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
1811             cm_ReleaseSCache(dscp);
1812             osi_Log1(afsd_logp, "RDR_CleanupFileEntry Not a Directory dscp=0x%p",
1813                      dscp);
1814             if (code)
1815                 goto on_error;
1816         }
1817     }
1818
1819     Fid.cell   = FileId.Cell;
1820     Fid.volume = FileId.Volume;
1821     Fid.vnode  = FileId.Vnode;
1822     Fid.unique = FileId.Unique;
1823     Fid.hash   = FileId.Hash;
1824
1825     code = cm_GetSCache(&Fid, dscp ? &dscp->fid : NULL, &scp, userp, &req);
1826     if (code) {
1827         osi_Log1(afsd_logp, "RDR_CleanupFileEntry cm_GetSCache object FID failure code=0x%x",
1828                  code);
1829         goto on_error;
1830     }
1831
1832     lock_ObtainWrite(&scp->rw);
1833     bScpLocked = TRUE;
1834     code = cm_SyncOp(scp, NULL, userp, &req, 0,
1835                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
1836     if (code) {
1837         osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp failure scp=0x%p code=0x%x",
1838                  scp, code);
1839         goto on_error;
1840     }
1841     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1842
1843     if (bLastHandle && (scp->fileType == CM_SCACHETYPE_FILE) &&
1844         scp->redirBufCount > 0)
1845     {
1846         LARGE_INTEGER heldExtents;
1847         AFSFileExtentCB extentList[1024];
1848         DWORD extentCount = 0;
1849         cm_buf_t *srbp;
1850         time_t now;
1851
1852         time(&now);
1853         heldExtents.QuadPart = 0;
1854
1855         for ( srbp = redirq_to_cm_buf_t(scp->redirQueueT);
1856               srbp;
1857               srbp = redirq_to_cm_buf_t(osi_QPrev(&srbp->redirq)))
1858         {
1859             extentList[extentCount].Flags = 0;
1860             extentList[extentCount].Length = cm_data.blockSize;
1861             extentList[extentCount].FileOffset.QuadPart = srbp->offset.QuadPart;
1862             extentList[extentCount].CacheOffset.QuadPart = srbp->datap - RDR_extentBaseAddress;
1863             lock_ObtainWrite(&buf_globalLock);
1864             srbp->redirReleaseRequested = now;
1865             lock_ReleaseWrite(&buf_globalLock);
1866             extentCount++;
1867
1868             if (extentCount == 1024) {
1869                 lock_ReleaseWrite(&scp->rw);
1870                 code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1871                 if (code) {
1872                     if (code == CM_ERROR_RETRY) {
1873                         /*
1874                          * The redirector either is not holding the extents or cannot let them
1875                          * go because they are otherwise in use.  At the moment, do nothing.
1876                          */
1877                     } else
1878                         break;
1879                 }
1880                 extentCount = 0;
1881                 bFlushFile = TRUE;
1882                 lock_ObtainWrite(&scp->rw);
1883             }
1884         }
1885
1886         if (code == 0 && extentCount > 0) {
1887             if (bScpLocked) {
1888                 lock_ReleaseWrite(&scp->rw);
1889                 bScpLocked = FALSE;
1890             }
1891             code = RDR_RequestExtentRelease(&scp->fid, heldExtents, extentCount, extentList);
1892             bFlushFile = TRUE;
1893         }
1894     }
1895
1896     /* No longer in use by redirector */
1897     if (!bScpLocked) {
1898         lock_ObtainWrite(&scp->rw);
1899         bScpLocked = TRUE;
1900     }
1901
1902     if (bLastHandle) {
1903         lock_AssertWrite(&scp->rw);
1904         scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
1905     }
1906
1907     /* If not a readonly object, flush dirty data and update metadata */
1908     if (!(scp->flags & CM_SCACHEFLAG_RO)) {
1909         if ((scp->fileType == CM_SCACHETYPE_FILE) && (bLastHandle || bFlushFile)) {
1910             /* Serialize with any outstanding AsyncStore operation */
1911             code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
1912             if (code == 0) {
1913                 cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
1914
1915                 code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
1916                                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1917                 /*
1918                  * If we only have 'i' bits, then we should still be able to
1919                  * set flush the file.
1920                  */
1921                 if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
1922                     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
1923                                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1924                 }
1925                 if (code == 0) {
1926                     if (bScpLocked) {
1927                         lock_ReleaseWrite(&scp->rw);
1928                         bScpLocked = FALSE;
1929                     }
1930
1931                     code = cm_FSync(scp, userp, &req, bScpLocked);
1932                 }
1933             }
1934             if (bLastHandle && code)
1935                 goto unlock;
1936         }
1937
1938         if (CleanupCB->ChangeTime.QuadPart) {
1939
1940             if (scp->fileType == CM_SCACHETYPE_FILE) {
1941                 /* Do not set length and other attributes at the same time */
1942                 if (scp->length.QuadPart != CleanupCB->AllocationSize.QuadPart) {
1943                     osi_Log2(afsd_logp, "RDR_CleanupFileEntry Length Change 0x%x -> 0x%x",
1944                              (afs_uint32)scp->length.QuadPart, (afs_uint32)CleanupCB->AllocationSize.QuadPart);
1945                     setAttr.mask |= CM_ATTRMASK_LENGTH;
1946                     setAttr.length.LowPart = CleanupCB->AllocationSize.LowPart;
1947                     setAttr.length.HighPart = CleanupCB->AllocationSize.HighPart;
1948
1949                     if (bScpLocked) {
1950                         lock_ReleaseWrite(&scp->rw);
1951                         bScpLocked = FALSE;
1952                     }
1953                     code = cm_SetAttr(scp, &setAttr, userp, &req);
1954                     if (code)
1955                         goto unlock;
1956                     setAttr.mask = 0;
1957                 }
1958             }
1959
1960             if (!bScpLocked) {
1961                 lock_ObtainWrite(&scp->rw);
1962                 bScpLocked = TRUE;
1963             }
1964
1965             if ((scp->unixModeBits & 0200) && (CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1966                 setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1967                 setAttr.unixModeBits = scp->unixModeBits & ~0222;
1968             } else if (!(scp->unixModeBits & 0200) && !(CleanupCB->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
1969                 setAttr.mask |= CM_ATTRMASK_UNIXMODEBITS;
1970                 setAttr.unixModeBits = scp->unixModeBits | 0222;
1971             }
1972         }
1973
1974         if (CleanupCB->LastWriteTime.QuadPart) {
1975             ft.dwLowDateTime = CleanupCB->LastWriteTime.LowPart;
1976             ft.dwHighDateTime = CleanupCB->LastWriteTime.HighPart;
1977
1978             cm_UnixTimeFromLargeSearchTime(&clientModTime, &ft);
1979             if (scp->clientModTime != clientModTime) {
1980                 setAttr.mask |= CM_ATTRMASK_CLIENTMODTIME;
1981                 setAttr.clientModTime = clientModTime;
1982             }
1983         }
1984
1985         /* call setattr */
1986         if (setAttr.mask) {
1987             if (bScpLocked) {
1988                 lock_ReleaseWrite(&scp->rw);
1989                 bScpLocked = FALSE;
1990             }
1991             code = cm_SetAttr(scp, &setAttr, userp, &req);
1992         } else
1993             code = 0;
1994     }
1995
1996   unlock:
1997     /* Now drop the lock enforcing the share access */
1998     if ( CleanupCB->FileAccess != AFS_FILE_ACCESS_NOLOCK) {
1999         unsigned int sLockType;
2000         LARGE_INTEGER LOffset, LLength;
2001
2002         if (CleanupCB->FileAccess == AFS_FILE_ACCESS_SHARED)
2003             sLockType = LOCKING_ANDX_SHARED_LOCK;
2004         else
2005             sLockType = 0;
2006
2007         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, CleanupCB->Identifier);
2008
2009         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
2010         LOffset.LowPart = SMB_FID_QLOCK_LOW;
2011         LLength.HighPart = 0;
2012         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
2013
2014         if (!bScpLocked) {
2015             lock_ObtainWrite(&scp->rw);
2016             bScpLocked = TRUE;
2017         }
2018
2019         code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
2020         if (code == 0)
2021         {
2022             code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
2023
2024             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
2025
2026             if (code == CM_ERROR_RANGE_NOT_LOCKED)
2027             {
2028                 osi_Log3(afsd_logp, "RDR_CleanupFileEntry Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
2029                          CleanupCB->FileAccess, CleanupCB->ProcessId, CleanupCB->Identifier);
2030
2031             }
2032         }
2033     }
2034
2035     if (bUnlockFile || bDeleteFile) {
2036         if (!bScpLocked) {
2037             lock_ObtainWrite(&scp->rw);
2038             bScpLocked = TRUE;
2039         }
2040         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2041                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2042         if (code) {
2043             osi_Log2(afsd_logp, "RDR_CleanupFileEntry cm_SyncOp (2) failure scp=0x%p code=0x%x",
2044                      scp, code);
2045             goto on_error;
2046         }
2047
2048         key = cm_GenerateKey(CM_SESSION_IFS, CleanupCB->ProcessId, 0);
2049
2050         /* the scp is now locked and current */
2051         code = cm_UnlockByKey(scp, key,
2052                               bDeleteFile ? CM_UNLOCK_FLAG_BY_FID : 0,
2053                               userp, &req);
2054
2055         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2056
2057         if (code)
2058             goto on_error;
2059     }
2060
2061   on_error:
2062     if (bDscpLocked)
2063         lock_ReleaseWrite(&dscp->rw);
2064     if (bScpLocked)
2065         lock_ReleaseWrite(&scp->rw);
2066
2067     if (code == 0 && dscp && bDeleteFile) {
2068         WCHAR FileName[260];
2069
2070         StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2071
2072         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2073             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2074         else
2075             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2076     }
2077
2078     if (code == 0) {
2079         if ( ResultBufferLength >=  sizeof( AFSFileCleanupResultCB))
2080         {
2081             (*ResultCB)->ResultBufferLength = sizeof( AFSFileCleanupResultCB);
2082             pResultCB = (AFSFileCleanupResultCB *)&(*ResultCB)->ResultData;
2083             pResultCB->ParentDataVersion.QuadPart = dscp ? dscp->dataVersion : 0;
2084         } else {
2085             (*ResultCB)->ResultBufferLength = 0;
2086         }
2087
2088         (*ResultCB)->ResultStatus = 0;
2089         osi_Log0(afsd_logp, "RDR_CleanupFileEntry SUCCESS");
2090     } else {
2091         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2092         (*ResultCB)->ResultStatus = status;
2093         osi_Log2(afsd_logp, "RDR_CleanupFileEntry FAILURE code=0x%x status=0x%x",
2094                   code, status);
2095     }
2096
2097     if (scp)
2098         cm_ReleaseSCache(scp);
2099     if (dscp)
2100         cm_ReleaseSCache(dscp);
2101
2102     return;
2103 }
2104
2105 void
2106 RDR_DeleteFileEntry( IN cm_user_t *userp,
2107                      IN AFSFileID ParentId,
2108                      IN ULONGLONG ProcessId,
2109                      IN WCHAR *FileNameCounted,
2110                      IN DWORD FileNameLength,
2111                      IN BOOL bWow64,
2112                      IN BOOL bCheckOnly,
2113                      IN DWORD ResultBufferLength,
2114                      IN OUT AFSCommResult **ResultCB)
2115 {
2116
2117     AFSFileDeleteResultCB *pResultCB = NULL;
2118     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2119     cm_fid_t            parentFid;
2120     afs_uint32          code;
2121     cm_scache_t *       dscp = NULL;
2122     cm_scache_t *       scp = NULL;
2123     afs_uint32          flags = 0;
2124     cm_attr_t           setAttr;
2125     cm_req_t            req;
2126     DWORD               status;
2127     wchar_t             FileName[260];
2128     cm_key_t            key;
2129
2130     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2131
2132     osi_Log4(afsd_logp, "RDR_DeleteFileEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2133               ParentId.Cell,  ParentId.Volume,
2134               ParentId.Vnode, ParentId.Unique);
2135     osi_Log2(afsd_logp, "... name=%S checkOnly=%x",
2136              osi_LogSaveStringW(afsd_logp, FileName),
2137              bCheckOnly);
2138
2139     RDR_InitReq(&req, bWow64);
2140     memset(&setAttr, 0, sizeof(cm_attr_t));
2141
2142     *ResultCB = (AFSCommResult *)malloc( size);
2143     if (!(*ResultCB)) {
2144         osi_Log0(afsd_logp, "RDR_DeleteFileEntry out of memory");
2145         return;
2146     }
2147
2148     memset( *ResultCB,
2149             '\0',
2150             size);
2151
2152     parentFid.cell   = ParentId.Cell;
2153     parentFid.volume = ParentId.Volume;
2154     parentFid.vnode  = ParentId.Vnode;
2155     parentFid.unique = ParentId.Unique;
2156     parentFid.hash   = ParentId.Hash;
2157
2158     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
2159     if (code) {
2160         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2161         if ( status == STATUS_INVALID_HANDLE)
2162             status = STATUS_OBJECT_PATH_INVALID;
2163         (*ResultCB)->ResultStatus = status;
2164         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
2165                   code, status);
2166         return;
2167     }
2168
2169     lock_ObtainWrite(&dscp->rw);
2170
2171     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
2172                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2173     if (code) {
2174         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2175         (*ResultCB)->ResultStatus = status;
2176         (*ResultCB)->ResultBufferLength = 0;
2177         lock_ReleaseWrite(&dscp->rw);
2178         cm_ReleaseSCache(dscp);
2179         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure dscp=0x%p code=0x%x status=0x%x",
2180                  dscp, code, status);
2181         return;
2182     }
2183
2184     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2185     lock_ReleaseWrite(&dscp->rw);
2186
2187     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2188         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2189         cm_ReleaseSCache(dscp);
2190         osi_Log1(afsd_logp, "RDR_DeleteFileEntry Not a Directory dscp=0x%p",
2191                  dscp);
2192         return;
2193     }
2194
2195     code = cm_Lookup(dscp, FileName, 0, userp, &req, &scp);
2196     if (code) {
2197         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2198         (*ResultCB)->ResultStatus = status;
2199         (*ResultCB)->ResultBufferLength = 0;
2200         cm_ReleaseSCache(dscp);
2201         osi_Log2(afsd_logp, "RDR_DeleteFileEntry cm_Lookup failure code=0x%x status=0x%x",
2202                  code, status);
2203         return;
2204     }
2205
2206     lock_ObtainWrite(&scp->rw);
2207     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_DELETE,
2208                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2209     if (code) {
2210         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2211         (*ResultCB)->ResultStatus = status;
2212         (*ResultCB)->ResultBufferLength = 0;
2213         lock_ReleaseWrite(&scp->rw);
2214         cm_ReleaseSCache(scp);
2215         cm_ReleaseSCache(dscp);
2216         osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
2217                  scp, code, status);
2218         return;
2219     }
2220
2221     if (!bCheckOnly) {
2222         /* Drop all locks since the file is being deleted */
2223         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2224                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2225         if (code) {
2226             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2227             (*ResultCB)->ResultStatus = status;
2228             (*ResultCB)->ResultBufferLength = 0;
2229             lock_ReleaseWrite(&scp->rw);
2230             cm_ReleaseSCache(scp);
2231             cm_ReleaseSCache(dscp);
2232             osi_Log3(afsd_logp, "RDR_DeleteFileEntry cm_SyncOp Lock failure scp=0x%p code=0x%x status=0x%x",
2233                      scp, code, status);
2234         }
2235
2236         /* the scp is now locked and current */
2237         key = cm_GenerateKey(CM_SESSION_IFS, ProcessId, 0);
2238
2239         code = cm_UnlockByKey(scp, key,
2240                               CM_UNLOCK_FLAG_BY_FID,
2241                               userp, &req);
2242
2243         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
2244         lock_ReleaseWrite(&scp->rw);
2245
2246         if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2247             code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2248         else
2249             code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2250     } else {
2251         lock_ReleaseWrite(&scp->rw);
2252     }
2253
2254     if (code == 0) {
2255         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
2256
2257         (*ResultCB)->ResultBufferLength = sizeof( AFSFileDeleteResultCB);
2258
2259         pResultCB = (AFSFileDeleteResultCB *)(*ResultCB)->ResultData;
2260
2261         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
2262         osi_Log0(afsd_logp, "RDR_DeleteFileEntry SUCCESS");
2263     } else {
2264         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2265         (*ResultCB)->ResultStatus = status;
2266         (*ResultCB)->ResultBufferLength = 0;
2267         osi_Log2(afsd_logp, "RDR_DeleteFileEntry FAILURE code=0x%x status=0x%x",
2268                   code, status);
2269     }
2270
2271     cm_ReleaseSCache(dscp);
2272     cm_ReleaseSCache(scp);
2273
2274     return;
2275 }
2276
2277 void
2278 RDR_RenameFileEntry( IN cm_user_t *userp,
2279                      IN WCHAR    *SourceFileNameCounted,
2280                      IN DWORD     SourceFileNameLength,
2281                      IN AFSFileID SourceFileId,
2282                      IN AFSFileRenameCB *pRenameCB,
2283                      IN BOOL bWow64,
2284                      IN DWORD ResultBufferLength,
2285                      IN OUT AFSCommResult **ResultCB)
2286 {
2287
2288     AFSFileRenameResultCB *pResultCB = NULL;
2289     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2290     AFSFileID              SourceParentId   = pRenameCB->SourceParentId;
2291     AFSFileID              TargetParentId   = pRenameCB->TargetParentId;
2292     WCHAR *                TargetFileNameCounted = pRenameCB->TargetName;
2293     DWORD                  TargetFileNameLength = pRenameCB->TargetNameLength;
2294     cm_fid_t               SourceParentFid;
2295     cm_fid_t               TargetParentFid;
2296     cm_fid_t               SourceFid;
2297     cm_fid_t               OrigTargetFid = {0,0,0,0,0};
2298     cm_fid_t               TargetFid;
2299     cm_scache_t *          oldDscp;
2300     cm_scache_t *          newDscp;
2301     cm_dirOp_t dirop;
2302     wchar_t                shortName[13];
2303     wchar_t                SourceFileName[260];
2304     wchar_t                TargetFileName[260];
2305     cm_dirFid_t            dfid;
2306     cm_req_t               req;
2307     afs_uint32             code;
2308     DWORD                  status;
2309
2310     RDR_InitReq(&req, bWow64);
2311
2312     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
2313     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
2314
2315     osi_Log4(afsd_logp, "RDR_RenameFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2316               SourceParentId.Cell,  SourceParentId.Volume,
2317               SourceParentId.Vnode, SourceParentId.Unique);
2318     osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
2319     osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2320               TargetParentId.Cell,  TargetParentId.Volume,
2321               TargetParentId.Vnode, TargetParentId.Unique);
2322     osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
2323
2324     *ResultCB = (AFSCommResult *)malloc( size);
2325     if (!(*ResultCB))
2326         return;
2327
2328     memset( *ResultCB,
2329             '\0',
2330             size);
2331
2332     pResultCB = (AFSFileRenameResultCB *)(*ResultCB)->ResultData;
2333
2334     if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
2335     {
2336         osi_Log2(afsd_logp, "RDR_RenameFileEntry Invalid Name Length: src %u target %u",
2337                  SourceFileNameLength, TargetFileNameLength);
2338         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
2339         return;
2340     }
2341
2342     SourceParentFid.cell   = SourceParentId.Cell;
2343     SourceParentFid.volume = SourceParentId.Volume;
2344     SourceParentFid.vnode  = SourceParentId.Vnode;
2345     SourceParentFid.unique = SourceParentId.Unique;
2346     SourceParentFid.hash   = SourceParentId.Hash;
2347
2348     TargetParentFid.cell   = TargetParentId.Cell;
2349     TargetParentFid.volume = TargetParentId.Volume;
2350     TargetParentFid.vnode  = TargetParentId.Vnode;
2351     TargetParentFid.unique = TargetParentId.Unique;
2352     TargetParentFid.hash   = TargetParentId.Hash;
2353
2354     code = cm_GetSCache(&SourceParentFid, NULL, &oldDscp, userp, &req);
2355     if (code) {
2356         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache source parent failed code 0x%x", code);
2357         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2358         if ( status == STATUS_INVALID_HANDLE)
2359             status = STATUS_OBJECT_PATH_INVALID;
2360         (*ResultCB)->ResultStatus = status;
2361         return;
2362     }
2363
2364     lock_ObtainWrite(&oldDscp->rw);
2365     code = cm_SyncOp(oldDscp, NULL, userp, &req, 0,
2366                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2367     if (code) {
2368         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp oldDscp 0x%p failed code 0x%x", oldDscp, code);
2369         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2370         if ( status == STATUS_INVALID_HANDLE)
2371             status = STATUS_OBJECT_PATH_INVALID;
2372         (*ResultCB)->ResultStatus = status;
2373         lock_ReleaseWrite(&oldDscp->rw);
2374         cm_ReleaseSCache(oldDscp);
2375         return;
2376     }
2377
2378     cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2379     lock_ReleaseWrite(&oldDscp->rw);
2380
2381
2382     if (oldDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2383         osi_Log1(afsd_logp, "RDR_RenameFileEntry oldDscp 0x%p not a directory", oldDscp);
2384         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2385         cm_ReleaseSCache(oldDscp);
2386         return;
2387     }
2388
2389     code = cm_GetSCache(&TargetParentFid, NULL, &newDscp, userp, &req);
2390     if (code) {
2391         osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target parent failed code 0x%x", code);
2392         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2393         (*ResultCB)->ResultStatus = status;
2394         cm_ReleaseSCache(oldDscp);
2395         return;
2396     }
2397
2398     lock_ObtainWrite(&newDscp->rw);
2399     code = cm_SyncOp(newDscp, NULL, userp, &req, 0,
2400                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2401     if (code) {
2402         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp newDscp 0x%p failed code 0x%x", newDscp, code);
2403         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2404         (*ResultCB)->ResultStatus = status;
2405         lock_ReleaseWrite(&newDscp->rw);
2406         cm_ReleaseSCache(oldDscp);
2407         cm_ReleaseSCache(newDscp);
2408         return;
2409     }
2410
2411     cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2412     lock_ReleaseWrite(&newDscp->rw);
2413
2414
2415     if (newDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2416         osi_Log1(afsd_logp, "RDR_RenameFileEntry newDscp 0x%p not a directory", newDscp);
2417         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2418         cm_ReleaseSCache(oldDscp);
2419         cm_ReleaseSCache(newDscp);
2420         return;
2421     }
2422
2423     /* Obtain the original FID just for debugging purposes */
2424     code = cm_BeginDirOp( oldDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2425     if (code == 0) {
2426         code = cm_BPlusDirLookup(&dirop, SourceFileName, &SourceFid);
2427         code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
2428         cm_EndDirOp(&dirop);
2429     }
2430
2431     code = cm_Rename( oldDscp, NULL, SourceFileName,
2432                       newDscp, TargetFileName, userp, &req);
2433     if (code == 0) {
2434         cm_scache_t *scp = 0;
2435         DWORD dwRemaining;
2436
2437         (*ResultCB)->ResultBufferLength = ResultBufferLength;
2438         dwRemaining = ResultBufferLength - sizeof( AFSFileRenameResultCB) + sizeof( AFSDirEnumEntry);
2439         (*ResultCB)->ResultStatus = 0;
2440
2441         pResultCB->SourceParentDataVersion.QuadPart = oldDscp->dataVersion;
2442         pResultCB->TargetParentDataVersion.QuadPart = newDscp->dataVersion;
2443
2444         osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p SUCCESS",
2445                  oldDscp, newDscp);
2446
2447         code = cm_BeginDirOp( newDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2448         if (code == 0) {
2449             code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
2450             cm_EndDirOp(&dirop);
2451         }
2452
2453         if (code != 0) {
2454             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_BPlusDirLookup failed code 0x%x",
2455                      code);
2456             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
2457             cm_ReleaseSCache(oldDscp);
2458             cm_ReleaseSCache(newDscp);
2459             return;
2460         }
2461
2462         osi_Log4(afsd_logp, "RDR_RenameFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2463                   TargetFid.cell,  TargetFid.volume,
2464                   TargetFid.vnode, TargetFid.unique);
2465
2466         code = cm_GetSCache(&TargetFid, &newDscp->fid, &scp, userp, &req);
2467         if (code) {
2468             osi_Log1(afsd_logp, "RDR_RenameFileEntry cm_GetSCache target failed code 0x%x", code);
2469             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2470             (*ResultCB)->ResultStatus = status;
2471             cm_ReleaseSCache(oldDscp);
2472             cm_ReleaseSCache(newDscp);
2473             return;
2474         }
2475
2476         /* Make sure the source vnode is current */
2477         lock_ObtainWrite(&scp->rw);
2478         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2479                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2480         if (code) {
2481             osi_Log2(afsd_logp, "RDR_RenameFileEntry cm_SyncOp scp 0x%p failed code 0x%x", scp, code);
2482             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2483             (*ResultCB)->ResultStatus = status;
2484             lock_ReleaseWrite(&scp->rw);
2485             cm_ReleaseSCache(oldDscp);
2486             cm_ReleaseSCache(newDscp);
2487             cm_ReleaseSCache(scp);
2488             return;
2489         }
2490
2491         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2492         lock_ReleaseWrite(&scp->rw);
2493
2494         if (cm_shortNames) {
2495             dfid.vnode = htonl(scp->fid.vnode);
2496             dfid.unique = htonl(scp->fid.unique);
2497
2498             if (!cm_Is8Dot3(TargetFileName))
2499                 cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
2500             else
2501                 shortName[0] = '\0';
2502         }
2503
2504         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
2505                                  newDscp, scp, userp, &req, TargetFileName, shortName,
2506                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
2507                                  0, NULL, &dwRemaining);
2508         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
2509         cm_ReleaseSCache(scp);
2510
2511         osi_Log0(afsd_logp, "RDR_RenameFileEntry SUCCESS");
2512     } else {
2513         osi_Log3(afsd_logp, "RDR_RenameFileEntry cm_Rename oldDscp 0x%p newDscp 0x%p failed code 0x%x",
2514                  oldDscp, newDscp, code);
2515         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2516         (*ResultCB)->ResultStatus = status;
2517         (*ResultCB)->ResultBufferLength = 0;
2518     }
2519
2520     cm_ReleaseSCache(oldDscp);
2521     cm_ReleaseSCache(newDscp);
2522     return;
2523 }
2524
2525 /*
2526  * AFS does not support cross-directory hard links but RDR_HardLinkFileEntry
2527  * is written as if AFS does.  The check for cross-directory links is
2528  * implemented in cm_Link().
2529  *
2530  * Windows supports optional ReplaceIfExists functionality.  The AFS file
2531  * server does not.  If the target name already exists and bReplaceIfExists
2532  * is true, check to see if the user has insert permission before calling
2533  * cm_Unlink() on the existing object.  If the user does not have insert
2534  * permission return STATUS_ACCESS_DENIED.
2535  */
2536
2537 void
2538 RDR_HardLinkFileEntry( IN cm_user_t *userp,
2539                        IN WCHAR    *SourceFileNameCounted,
2540                        IN DWORD     SourceFileNameLength,
2541                        IN AFSFileID SourceFileId,
2542                        IN AFSFileHardLinkCB *pHardLinkCB,
2543                        IN BOOL bWow64,
2544                        IN DWORD ResultBufferLength,
2545                        IN OUT AFSCommResult **ResultCB)
2546 {
2547
2548     AFSFileHardLinkResultCB *pResultCB = NULL;
2549     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2550     AFSFileID              SourceParentId   = pHardLinkCB->SourceParentId;
2551     AFSFileID              TargetParentId   = pHardLinkCB->TargetParentId;
2552     WCHAR *                TargetFileNameCounted = pHardLinkCB->TargetName;
2553     DWORD                  TargetFileNameLength = pHardLinkCB->TargetNameLength;
2554     cm_fid_t               SourceParentFid;
2555     cm_fid_t               TargetParentFid;
2556     cm_fid_t               SourceFid;
2557     cm_fid_t               OrigTargetFid = {0,0,0,0,0};
2558     cm_scache_t *          srcDscp = NULL;
2559     cm_scache_t *          targetDscp = NULL;
2560     cm_scache_t *          srcScp = NULL;
2561     cm_dirOp_t             dirop;
2562     wchar_t                shortName[13];
2563     wchar_t                SourceFileName[260];
2564     wchar_t                TargetFileName[260];
2565     cm_dirFid_t            dfid;
2566     cm_req_t               req;
2567     afs_uint32             code;
2568     DWORD                  status;
2569
2570     RDR_InitReq(&req, bWow64);
2571
2572     StringCchCopyNW(SourceFileName, 260, SourceFileNameCounted, SourceFileNameLength / sizeof(WCHAR));
2573     StringCchCopyNW(TargetFileName, 260, TargetFileNameCounted, TargetFileNameLength / sizeof(WCHAR));
2574
2575     osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Source Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2576               SourceParentId.Cell,  SourceParentId.Volume,
2577               SourceParentId.Vnode, SourceParentId.Unique);
2578     osi_Log2(afsd_logp, "... Source Name=%S Length %u", osi_LogSaveStringW(afsd_logp, SourceFileName), SourceFileNameLength);
2579     osi_Log4(afsd_logp, "... Target Parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2580               TargetParentId.Cell,  TargetParentId.Volume,
2581               TargetParentId.Vnode, TargetParentId.Unique);
2582     osi_Log2(afsd_logp, "... Target Name=%S Length %u", osi_LogSaveStringW(afsd_logp, TargetFileName), TargetFileNameLength);
2583
2584     *ResultCB = (AFSCommResult *)malloc( size);
2585     if (!(*ResultCB))
2586         return;
2587
2588     memset( *ResultCB,
2589             '\0',
2590             size);
2591
2592     pResultCB = (AFSFileHardLinkResultCB *)(*ResultCB)->ResultData;
2593
2594     if (SourceFileNameLength == 0 || TargetFileNameLength == 0)
2595     {
2596         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry Invalid Name Length: src %u target %u",
2597                  SourceFileNameLength, TargetFileNameLength);
2598         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
2599         return;
2600     }
2601
2602     SourceFid.cell   = SourceFileId.Cell;
2603     SourceFid.volume = SourceFileId.Volume;
2604     SourceFid.vnode  = SourceFileId.Vnode;
2605     SourceFid.unique = SourceFileId.Unique;
2606     SourceFid.hash   = SourceFileId.Hash;
2607
2608     SourceParentFid.cell   = SourceParentId.Cell;
2609     SourceParentFid.volume = SourceParentId.Volume;
2610     SourceParentFid.vnode  = SourceParentId.Vnode;
2611     SourceParentFid.unique = SourceParentId.Unique;
2612     SourceParentFid.hash   = SourceParentId.Hash;
2613
2614     TargetParentFid.cell   = TargetParentId.Cell;
2615     TargetParentFid.volume = TargetParentId.Volume;
2616     TargetParentFid.vnode  = TargetParentId.Vnode;
2617     TargetParentFid.unique = TargetParentId.Unique;
2618     TargetParentFid.hash   = TargetParentId.Hash;
2619
2620     code = cm_GetSCache(&SourceFid, NULL, &srcScp, userp, &req);
2621     if (code) {
2622         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache source failed code 0x%x", code);
2623         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2624         (*ResultCB)->ResultStatus = status;
2625         return;
2626     }
2627
2628     code = cm_GetSCache(&TargetParentFid, NULL, &targetDscp, userp, &req);
2629     if (code) {
2630         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target parent failed code 0x%x", code);
2631         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2632         (*ResultCB)->ResultStatus = status;
2633         cm_ReleaseSCache(srcScp);
2634         return;
2635     }
2636
2637     lock_ObtainWrite(&targetDscp->rw);
2638     code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT,
2639                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2640     if (code) {
2641         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp targetDscp 0x%p failed code 0x%x", targetDscp, code);
2642         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2643         (*ResultCB)->ResultStatus = status;
2644         lock_ReleaseWrite(&targetDscp->rw);
2645         cm_ReleaseSCache(srcScp);
2646         cm_ReleaseSCache(targetDscp);
2647         return;
2648     }
2649
2650     cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2651     lock_ReleaseWrite(&targetDscp->rw);
2652
2653     if (targetDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2654         osi_Log1(afsd_logp, "RDR_HardLinkFileEntry targetDscp 0x%p not a directory", targetDscp);
2655         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2656         cm_ReleaseSCache(srcScp);
2657         cm_ReleaseSCache(targetDscp);
2658         return;
2659     }
2660
2661     if ( cm_FidCmp(&SourceParentFid, &TargetParentFid) ) {
2662         code = cm_GetSCache(&SourceParentFid, NULL, &srcDscp, userp, &req);
2663         if (code) {
2664             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache source parent failed code 0x%x", code);
2665             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2666             if ( status == STATUS_INVALID_HANDLE)
2667                 status = STATUS_OBJECT_PATH_INVALID;
2668             (*ResultCB)->ResultStatus = status;
2669             cm_ReleaseSCache(srcScp);
2670             cm_ReleaseSCache(targetDscp);
2671             return;
2672         }
2673
2674         lock_ObtainWrite(&srcDscp->rw);
2675         code = cm_SyncOp(srcDscp, NULL, userp, &req, 0,
2676                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2677         if (code) {
2678             osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp srcDscp 0x%p failed code 0x%x", srcDscp, code);
2679             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2680             if ( status == STATUS_INVALID_HANDLE)
2681                 status = STATUS_OBJECT_PATH_INVALID;
2682             (*ResultCB)->ResultStatus = status;
2683             lock_ReleaseWrite(&srcDscp->rw);
2684             if (srcDscp != targetDscp)
2685                 cm_ReleaseSCache(srcDscp);
2686             cm_ReleaseSCache(targetDscp);
2687             cm_ReleaseSCache(srcScp);
2688             return;
2689         }
2690
2691         cm_SyncOpDone(srcDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2692         lock_ReleaseWrite(&srcDscp->rw);
2693
2694         if (srcDscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2695             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry srcDscp 0x%p not a directory", srcDscp);
2696             (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2697             if (srcDscp != targetDscp)
2698                 cm_ReleaseSCache(srcDscp);
2699             cm_ReleaseSCache(targetDscp);
2700             cm_ReleaseSCache(srcScp);
2701             return;
2702         }
2703     } else {
2704         srcDscp = targetDscp;
2705     }
2706
2707     /* Obtain the target FID if it exists */
2708     code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2709     if (code == 0) {
2710         code = cm_BPlusDirLookup(&dirop, TargetFileName, &OrigTargetFid);
2711         cm_EndDirOp(&dirop);
2712     }
2713
2714     if (OrigTargetFid.vnode) {
2715
2716         /* An object exists with the target name */
2717         if (!pHardLinkCB->bReplaceIfExists) {
2718             osi_Log0(afsd_logp, "RDR_HardLinkFileEntry target name collision and !ReplaceIfExists");
2719             (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_COLLISION;
2720             if (srcDscp != targetDscp)
2721                 cm_ReleaseSCache(srcDscp);
2722             cm_ReleaseSCache(targetDscp);
2723             cm_ReleaseSCache(srcScp);
2724             return;
2725         }
2726
2727         lock_ObtainWrite(&targetDscp->rw);
2728         code = cm_SyncOp(targetDscp, NULL, userp, &req, PRSFS_INSERT | PRSFS_DELETE,
2729                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2730         if (code) {
2731             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2732             (*ResultCB)->ResultStatus = status;
2733             lock_ReleaseWrite(&srcDscp->rw);
2734             if (srcDscp != targetDscp)
2735                 cm_ReleaseSCache(srcDscp);
2736             cm_ReleaseSCache(targetDscp);
2737             cm_ReleaseSCache(srcScp);
2738             return;
2739         }
2740         cm_SyncOpDone(targetDscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2741         lock_ReleaseWrite(&targetDscp->rw);
2742
2743         code = cm_Unlink(targetDscp, NULL, TargetFileName, userp, &req);
2744         if (code) {
2745             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_Unlink code 0x%x", code);
2746             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2747             (*ResultCB)->ResultStatus = status;
2748             lock_ReleaseWrite(&srcDscp->rw);
2749             if (srcDscp != targetDscp)
2750                 cm_ReleaseSCache(srcDscp);
2751             cm_ReleaseSCache(targetDscp);
2752             cm_ReleaseSCache(srcScp);
2753             return;
2754         }
2755     }
2756
2757     code = cm_Link( targetDscp, TargetFileName, srcScp, 0, userp, &req);
2758     if (code == 0) {
2759         cm_fid_t TargetFid;
2760         cm_scache_t *targetScp = 0;
2761         DWORD dwRemaining;
2762
2763         (*ResultCB)->ResultBufferLength = ResultBufferLength;
2764         dwRemaining = ResultBufferLength - sizeof( AFSFileHardLinkResultCB) + sizeof( AFSDirEnumEntry);
2765         (*ResultCB)->ResultStatus = 0;
2766
2767         pResultCB->SourceParentDataVersion.QuadPart = srcDscp->dataVersion;
2768         pResultCB->TargetParentDataVersion.QuadPart = targetDscp->dataVersion;
2769
2770         osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p SUCCESS",
2771                  srcDscp, targetDscp);
2772
2773         code = cm_BeginDirOp( targetDscp, userp, &req, CM_DIRLOCK_READ, CM_DIROP_FLAG_NONE, &dirop);
2774         if (code == 0) {
2775             code = cm_BPlusDirLookup(&dirop, TargetFileName, &TargetFid);
2776             cm_EndDirOp(&dirop);
2777         }
2778
2779         if (code != 0) {
2780             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_BPlusDirLookup failed code 0x%x",
2781                      code);
2782             (*ResultCB)->ResultStatus = STATUS_OBJECT_PATH_INVALID;
2783             if (srcDscp != targetDscp)
2784                 cm_ReleaseSCache(srcDscp);
2785             cm_ReleaseSCache(srcScp);
2786             cm_ReleaseSCache(targetDscp);
2787             return;
2788         }
2789
2790         osi_Log4(afsd_logp, "RDR_HardLinkFileEntry Target FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2791                   TargetFid.cell,  TargetFid.volume,
2792                   TargetFid.vnode, TargetFid.unique);
2793
2794         code = cm_GetSCache(&TargetFid, &targetDscp->fid, &targetScp, userp, &req);
2795         if (code) {
2796             osi_Log1(afsd_logp, "RDR_HardLinkFileEntry cm_GetSCache target failed code 0x%x", code);
2797             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2798             (*ResultCB)->ResultStatus = status;
2799             if (srcDscp != targetDscp)
2800                 cm_ReleaseSCache(srcDscp);
2801             cm_ReleaseSCache(srcScp);
2802             cm_ReleaseSCache(targetDscp);
2803             return;
2804         }
2805
2806         /* Make sure the source vnode is current */
2807         lock_ObtainWrite(&targetScp->rw);
2808         code = cm_SyncOp(targetScp, NULL, userp, &req, 0,
2809                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2810         if (code) {
2811             osi_Log2(afsd_logp, "RDR_HardLinkFileEntry cm_SyncOp scp 0x%p failed code 0x%x",
2812                      targetScp, code);
2813             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2814             (*ResultCB)->ResultStatus = status;
2815             lock_ReleaseWrite(&targetScp->rw);
2816             cm_ReleaseSCache(targetScp);
2817             if (srcDscp != targetDscp)
2818                 cm_ReleaseSCache(srcDscp);
2819             cm_ReleaseSCache(srcScp);
2820             cm_ReleaseSCache(targetDscp);
2821             return;
2822         }
2823
2824         cm_SyncOpDone(targetScp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2825         lock_ReleaseWrite(&targetScp->rw);
2826
2827         if (cm_shortNames) {
2828             dfid.vnode = htonl(targetScp->fid.vnode);
2829             dfid.unique = htonl(targetScp->fid.unique);
2830
2831             if (!cm_Is8Dot3(TargetFileName))
2832                 cm_Gen8Dot3NameIntW(TargetFileName, &dfid, shortName, NULL);
2833             else
2834                 shortName[0] = '\0';
2835         }
2836
2837         RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
2838                                  targetDscp, targetScp, userp, &req, TargetFileName, shortName,
2839                                  RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
2840                                  0, NULL, &dwRemaining);
2841         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
2842         cm_ReleaseSCache(targetScp);
2843
2844         osi_Log0(afsd_logp, "RDR_HardLinkFileEntry SUCCESS");
2845     } else {
2846         osi_Log3(afsd_logp, "RDR_HardLinkFileEntry cm_Link srcDscp 0x%p targetDscp 0x%p failed code 0x%x",
2847                  srcDscp, targetDscp, code);
2848         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2849         (*ResultCB)->ResultStatus = status;
2850         (*ResultCB)->ResultBufferLength = 0;
2851     }
2852
2853     cm_ReleaseSCache(srcScp);
2854     if (srcDscp != targetDscp)
2855         cm_ReleaseSCache(srcDscp);
2856     cm_ReleaseSCache(targetDscp);
2857     return;
2858 }
2859
2860
2861 void
2862 RDR_CreateSymlinkEntry( IN cm_user_t *userp,
2863                         IN AFSFileID FileId,
2864                         IN WCHAR *FileNameCounted,
2865                         IN DWORD FileNameLength,
2866                         IN AFSCreateSymlinkCB *SymlinkCB,
2867                         IN BOOL bWow64,
2868                         IN DWORD ResultBufferLength,
2869                         IN OUT AFSCommResult **ResultCB)
2870 {
2871     AFSCreateSymlinkResultCB *pResultCB = NULL;
2872     size_t size = sizeof(AFSCommResult) + ResultBufferLength - 1;
2873     cm_fid_t            parentFid;
2874     cm_fid_t            Fid;
2875     afs_uint32          code;
2876     cm_scache_t *       dscp = NULL;
2877     afs_uint32          flags = 0;
2878     cm_attr_t           setAttr;
2879     cm_scache_t *       scp = NULL;
2880     cm_req_t            req;
2881     DWORD               status;
2882     wchar_t             FileName[260];
2883     char               *TargetPath = NULL;
2884
2885     StringCchCopyNW(FileName, 260, FileNameCounted, FileNameLength / sizeof(WCHAR));
2886     TargetPath = cm_Utf16ToUtf8Alloc( SymlinkCB->TargetName,  SymlinkCB->TargetNameLength / sizeof(WCHAR), NULL);
2887
2888     osi_Log4( afsd_logp, "RDR_CreateSymlinkEntry parent FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
2889               SymlinkCB->ParentId.Cell, SymlinkCB->ParentId.Volume,
2890               SymlinkCB->ParentId.Vnode, SymlinkCB->ParentId.Unique);
2891     osi_Log1(afsd_logp, "... name=%S", osi_LogSaveStringW(afsd_logp, FileName));
2892
2893     RDR_InitReq(&req, bWow64);
2894     memset(&setAttr, 0, sizeof(cm_attr_t));
2895
2896     *ResultCB = (AFSCommResult *)malloc(size);
2897     if (!(*ResultCB)) {
2898         osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry out of memory");
2899         free(TargetPath);
2900         return;
2901     }
2902
2903     memset( *ResultCB,
2904             '\0',
2905             size);
2906
2907     parentFid.cell   = SymlinkCB->ParentId.Cell;
2908     parentFid.volume = SymlinkCB->ParentId.Volume;
2909     parentFid.vnode  = SymlinkCB->ParentId.Vnode;
2910     parentFid.unique = SymlinkCB->ParentId.Unique;
2911     parentFid.hash   = SymlinkCB->ParentId.Hash;
2912
2913     code = cm_GetSCache(&parentFid, NULL, &dscp, userp, &req);
2914     if (code) {
2915         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2916         (*ResultCB)->ResultStatus = status;
2917         if ( status == STATUS_INVALID_HANDLE)
2918             status = STATUS_OBJECT_PATH_INVALID;
2919         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry cm_GetSCache ParentFID failure code=0x%x status=0x%x",
2920                   code, status);
2921         free(TargetPath);
2922         return;
2923     }
2924
2925     lock_ObtainWrite(&dscp->rw);
2926     code = cm_SyncOp(dscp, NULL, userp, &req, 0,
2927                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2928     if (code) {
2929         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2930         (*ResultCB)->ResultStatus = status;
2931         lock_ReleaseWrite(&dscp->rw);
2932         cm_ReleaseSCache(dscp);
2933         osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) dscp=0x%p code=0x%x status=0x%x",
2934                  dscp, code, status);
2935         free(TargetPath);
2936         return;
2937     }
2938
2939     cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2940     lock_ReleaseWrite(&dscp->rw);
2941
2942     if (dscp->fileType != CM_SCACHETYPE_DIRECTORY) {
2943         (*ResultCB)->ResultStatus = STATUS_NOT_A_DIRECTORY;
2944         cm_ReleaseSCache(dscp);
2945         osi_Log1(afsd_logp, "RDR_CreateSymlinkEntry Not a Directory dscp=0x%p",
2946                  dscp);
2947         free(TargetPath);
2948         return;
2949     }
2950
2951     Fid.cell   = FileId.Cell;
2952     Fid.volume = FileId.Volume;
2953     Fid.vnode  = FileId.Vnode;
2954     Fid.unique = FileId.Unique;
2955     Fid.hash   = FileId.Hash;
2956
2957     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
2958     if (code) {
2959         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2960         (*ResultCB)->ResultStatus = status;
2961         if ( status == STATUS_INVALID_HANDLE)
2962             status = STATUS_OBJECT_PATH_INVALID;
2963         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry cm_GetSCache FID failure code=0x%x status=0x%x",
2964                   code, status);
2965         free(TargetPath);
2966         return;
2967     }
2968
2969     lock_ObtainWrite(&scp->rw);
2970     code = cm_SyncOp(scp, NULL, userp, &req, 0,
2971                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2972     if (code) {
2973         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2974         (*ResultCB)->ResultStatus = status;
2975         lock_ReleaseWrite(&scp->rw);
2976         cm_ReleaseSCache(scp);
2977         osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (1) scp=0x%p code=0x%x status=0x%x",
2978                  scp, code, status);
2979         free(TargetPath);
2980         return;
2981     }
2982
2983     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2984     lock_ReleaseWrite(&scp->rw);
2985
2986     /* Remove the temporary object */
2987     if (scp->fileType == CM_SCACHETYPE_DIRECTORY)
2988         code = cm_RemoveDir(dscp, NULL, FileName, userp, &req);
2989     else
2990         code = cm_Unlink(dscp, NULL, FileName, userp, &req);
2991     cm_ReleaseSCache(scp);
2992     scp = NULL;
2993     if (code && code != CM_ERROR_NOSUCHFILE) {
2994         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
2995         (*ResultCB)->ResultStatus = status;
2996         cm_ReleaseSCache(dscp);
2997         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry Unable to delete file dscp=0x%p code=0x%x",
2998                  dscp, code);
2999         free(TargetPath);
3000         return;
3001     }
3002
3003     /*
3004      * The target path is going to be provided by the redirector in one of the following forms:
3005      *
3006      * 1. Relative path.
3007      * 2. Absolute path prefaced as \??\UNC\<server>\<share>\<path>
3008      * 3. Absolute path prefaced as \??\<drive-letter>:\<path>
3009      *
3010      * Relative paths can be used with just slash conversion.  Absolute paths must be converted.
3011      * UNC paths with a server name that matches cm_NetbiosName then the path is an AFS path and
3012      * it must be converted to /<server>/<share>/<path>.  Other UNC paths must be converted to
3013      * msdfs:\\<server>\<share>\<path>.  Local disk paths should be converted to
3014      * msdfs:<drive-letter>:<path>.
3015      */
3016
3017     if ( TargetPath[0] == '\\' ) {
3018         size_t nbNameLen = strlen(cm_NetbiosName);
3019         size_t len;
3020         char  *s;
3021
3022         if ( strncmp(TargetPath, "\\??\\UNC\\", 8) == 0) {
3023
3024             if (strncmp(&TargetPath[8], cm_NetbiosName, nbNameLen) == 0 &&
3025                 TargetPath[8 + nbNameLen] == '\\')
3026             {
3027                 /* AFS path */
3028                 s = strdup(&TargetPath[8 + nbNameLen]);
3029                 free(TargetPath);
3030                 TargetPath = s;
3031                 for (; *s; s++) {
3032                     if (*s == '\\')
3033                         *s = '/';
3034                 }
3035             } else {
3036                 /*
3037                  * non-AFS UNC path (msdfs:\\server\share\path)
3038                  * strlen("msdfs:\\") == 7 + 1 for the NUL
3039                  */
3040                 len = 8 + strlen(&TargetPath[7]);
3041                 s = malloc(8 + strlen(&TargetPath[7]));
3042                 StringCbCopy(s, len, "msdfs:\\");
3043                 StringCbCat(s, len, &TargetPath[7]);
3044                 free(TargetPath);
3045                 TargetPath = s;
3046             }
3047         } else {
3048             /* non-UNC path (msdfs:<drive>:\<path> */
3049             s = strdup(&TargetPath[4]);
3050             free(TargetPath);
3051             TargetPath = s;
3052         }
3053
3054     } else {
3055         /* relative paths require slash conversion */
3056         char *s = TargetPath;
3057         for (; *s; s++) {
3058             if (*s == '\\')
3059                 *s = '/';
3060         }
3061     }
3062
3063     /* Use current time */
3064     setAttr.mask = CM_ATTRMASK_UNIXMODEBITS | CM_ATTRMASK_CLIENTMODTIME;
3065     setAttr.unixModeBits = 0755;
3066     setAttr.clientModTime = time(NULL);
3067
3068     code = cm_SymLink(dscp, FileName, TargetPath, flags, &setAttr, userp, &req, &scp);
3069     free(TargetPath);
3070
3071     if (code == 0) {
3072         wchar_t shortName[13]=L"";
3073         cm_dirFid_t dfid;
3074         DWORD dwRemaining;
3075
3076         if (dscp->flags & CM_SCACHEFLAG_ANYWATCH) {
3077             smb_NotifyChange(FILE_ACTION_ADDED,
3078                              FILE_NOTIFY_CHANGE_DIR_NAME,
3079                              dscp, FileName, NULL, TRUE);
3080         }
3081
3082         (*ResultCB)->ResultStatus = 0;  // We will be able to fit all the data in here
3083
3084         (*ResultCB)->ResultBufferLength = sizeof( AFSCreateSymlinkResultCB);
3085
3086         pResultCB = (AFSCreateSymlinkResultCB *)(*ResultCB)->ResultData;
3087
3088         dwRemaining = ResultBufferLength - sizeof( AFSCreateSymlinkResultCB) + sizeof( AFSDirEnumEntry);
3089
3090         lock_ObtainWrite(&dscp->rw);
3091         code = cm_SyncOp(dscp, NULL, userp, &req, 0,
3092                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3093         if (code) {
3094             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3095             (*ResultCB)->ResultStatus = status;
3096             lock_ReleaseWrite(&dscp->rw);
3097             cm_ReleaseSCache(dscp);
3098             cm_ReleaseSCache(scp);
3099             osi_Log3(afsd_logp, "RDR_CreateSymlinkEntry cm_SyncOp failure (2) dscp=0x%p code=0x%x status=0x%x",
3100                       dscp, code, status);
3101             return;
3102         }
3103
3104         pResultCB->ParentDataVersion.QuadPart = dscp->dataVersion;
3105
3106         cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3107         lock_ReleaseWrite(&dscp->rw);
3108
3109         if (cm_shortNames) {
3110             dfid.vnode = htonl(scp->fid.vnode);
3111             dfid.unique = htonl(scp->fid.unique);
3112
3113             if (!cm_Is8Dot3(FileName))
3114                 cm_Gen8Dot3NameIntW(FileName, &dfid, shortName, NULL);
3115             else
3116                 shortName[0] = '\0';
3117         }
3118
3119         code = RDR_PopulateCurrentEntry(&pResultCB->DirEnum, dwRemaining,
3120                                         dscp, scp, userp, &req, FileName, shortName,
3121                                         RDR_POP_FOLLOW_MOUNTPOINTS | RDR_POP_EVALUATE_SYMLINKS,
3122                                         0, NULL, &dwRemaining);
3123         cm_ReleaseSCache(scp);
3124         (*ResultCB)->ResultBufferLength = ResultBufferLength - dwRemaining;
3125         osi_Log0(afsd_logp, "RDR_CreateSymlinkEntry SUCCESS");
3126     } else {
3127         (*ResultCB)->ResultStatus = STATUS_FILE_DELETED;
3128         (*ResultCB)->ResultBufferLength = 0;
3129         osi_Log2(afsd_logp, "RDR_CreateSymlinkEntry FAILURE code=0x%x status=0x%x",
3130                   code, STATUS_FILE_DELETED);
3131     }
3132
3133     cm_ReleaseSCache(dscp);
3134
3135     return;
3136 }
3137
3138
3139 void
3140 RDR_FlushFileEntry( IN cm_user_t *userp,
3141                     IN AFSFileID FileId,
3142                     IN BOOL bWow64,
3143                     IN DWORD ResultBufferLength,
3144                     IN OUT AFSCommResult **ResultCB)
3145 {
3146     cm_scache_t *scp = NULL;
3147     cm_fid_t    Fid;
3148     afs_uint32  code;
3149     cm_req_t    req;
3150     DWORD       status;
3151 #ifdef ODS_DEBUG
3152     char        dbgstr[1024];
3153 #endif
3154
3155     RDR_InitReq(&req, bWow64);
3156
3157     osi_Log4(afsd_logp, "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x",
3158               FileId.Cell, FileId.Volume,
3159               FileId.Vnode, FileId.Unique);
3160 #ifdef ODS_DEBUG
3161     snprintf( dbgstr, 1024,
3162               "RDR_FlushFileEntry File FID cell 0x%x vol 0x%x vno 0x%x uniq 0x%x\n",
3163               FileId.Cell, FileId.Volume,
3164               FileId.Vnode, FileId.Unique);
3165     OutputDebugStringA( dbgstr);
3166 #endif
3167
3168     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
3169     if (!(*ResultCB)) {
3170         osi_Log0(afsd_logp, "RDR_FlushFileEntry out of memory");
3171         return;
3172     }
3173
3174     memset( *ResultCB,
3175             '\0',
3176             sizeof( AFSCommResult));
3177
3178     /* Process the release */
3179     Fid.cell = FileId.Cell;
3180     Fid.volume = FileId.Volume;
3181     Fid.vnode = FileId.Vnode;
3182     Fid.unique = FileId.Unique;
3183     Fid.hash = FileId.Hash;
3184
3185     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3186     if (code) {
3187         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3188         (*ResultCB)->ResultStatus = status;
3189         osi_Log2(afsd_logp, "RDR_FlushFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
3190                   code, status);
3191         return;
3192     }
3193
3194     lock_ObtainWrite(&scp->rw);
3195     if (scp->flags & CM_SCACHEFLAG_DELETED) {
3196         lock_ReleaseWrite(&scp->rw);
3197         (*ResultCB)->ResultStatus = STATUS_INVALID_HANDLE;
3198         return;
3199     }
3200
3201     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3202                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3203     if (code) {
3204         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3205         (*ResultCB)->ResultStatus = status;
3206         lock_ReleaseWrite(&scp->rw);
3207         cm_ReleaseSCache(scp);
3208         osi_Log3(afsd_logp, "RDR_FlushFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
3209                  scp, code, status);
3210         return;
3211     }
3212
3213     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3214     lock_ReleaseWrite(&scp->rw);
3215
3216     code = cm_FSync(scp, userp, &req, FALSE);
3217     cm_ReleaseSCache(scp);
3218
3219     if (code) {
3220         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3221         (*ResultCB)->ResultStatus = status;
3222         osi_Log2(afsd_logp, "RDR_FlushFileEntry FAILURE code=0x%x status=0x%x",
3223                   code, status);
3224     } else {
3225         (*ResultCB)->ResultStatus = 0;
3226         osi_Log0(afsd_logp, "RDR_FlushFileEntry SUCCESS");
3227     }
3228     (*ResultCB)->ResultBufferLength = 0;
3229
3230     return;
3231 }
3232
3233 afs_uint32
3234 RDR_CheckAccess( IN cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp,
3235                  ULONG access,
3236                  ULONG *granted)
3237 {
3238     ULONG afs_acc, afs_gr;
3239     BOOLEAN file, dir;
3240     afs_uint32 code = 0;
3241
3242     file = (scp->fileType == CM_SCACHETYPE_FILE);
3243     dir = !file;
3244
3245     /* access definitions from prs_fs.h */
3246     afs_acc = 0;
3247     if (access & FILE_READ_DATA)
3248         afs_acc |= PRSFS_READ;
3249     if (access & FILE_READ_EA || access & FILE_READ_ATTRIBUTES)
3250         afs_acc |= PRSFS_READ;
3251     if (file && ((access & FILE_WRITE_DATA) || (access & FILE_APPEND_DATA)))
3252         afs_acc |= PRSFS_WRITE;
3253     if (access & FILE_WRITE_EA || access & FILE_WRITE_ATTRIBUTES)
3254         afs_acc |= PRSFS_WRITE;
3255     if (dir && ((access & FILE_ADD_FILE) || (access & FILE_ADD_SUBDIRECTORY)))
3256         afs_acc |= PRSFS_INSERT;
3257     if (dir && (access & FILE_LIST_DIRECTORY))
3258         afs_acc |= PRSFS_LOOKUP;
3259     if (file && (access & FILE_EXECUTE))
3260         afs_acc |= PRSFS_WRITE;
3261     if (dir && (access & FILE_TRAVERSE))
3262         afs_acc |= PRSFS_READ;
3263     if (dir && (access & FILE_DELETE_CHILD))
3264         afs_acc |= PRSFS_DELETE;
3265     if ((access & DELETE))
3266         afs_acc |= PRSFS_DELETE;
3267
3268     /* check ACL with server */
3269     lock_ObtainWrite(&scp->rw);
3270     while (1)
3271     {
3272         if (cm_HaveAccessRights(scp, userp, reqp, afs_acc, &afs_gr))
3273         {
3274             break;
3275         }
3276         else
3277         {
3278             /* we don't know the required access rights */
3279             code = cm_GetAccessRights(scp, userp, reqp);
3280             if (code)
3281                 break;
3282             continue;
3283         }
3284     }
3285     lock_ReleaseWrite(&(scp->rw));
3286
3287     if (code == 0) {
3288         *granted = 0;
3289         if (afs_gr & PRSFS_READ)
3290             *granted |= FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE;
3291         if (afs_gr & PRSFS_WRITE)
3292             *granted |= FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES | FILE_EXECUTE;
3293         if (afs_gr & PRSFS_INSERT)
3294             *granted |= (dir ? FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY : 0) | (file ? FILE_ADD_SUBDIRECTORY : 0);
3295         if (afs_gr & PRSFS_LOOKUP)
3296             *granted |= (dir ? FILE_LIST_DIRECTORY : 0);
3297         if (afs_gr & PRSFS_DELETE)
3298             *granted |= FILE_DELETE_CHILD | DELETE;
3299         if (afs_gr & PRSFS_LOCK)
3300             *granted |= 0;
3301         if (afs_gr & PRSFS_ADMINISTER)
3302             *granted |= 0;
3303
3304         *granted |= SYNCHRONIZE | READ_CONTROL;
3305
3306         /* don't give more access than what was requested */
3307         *granted &= access;
3308         osi_Log3(afsd_logp, "RDR_CheckAccess SUCCESS scp=0x%p requested=0x%x granted=0x%x", scp, access, *granted);
3309     } else
3310         osi_Log2(afsd_logp, "RDR_CheckAccess FAILURE scp=0x%p code=0x%x",
3311                  scp, code);
3312
3313     return code;
3314 }
3315
3316 void
3317 RDR_OpenFileEntry( IN cm_user_t *userp,
3318                    IN AFSFileID FileId,
3319                    IN AFSFileOpenCB *OpenCB,
3320                    IN BOOL bWow64,
3321                    IN BOOL bHoldFid,
3322                    IN DWORD ResultBufferLength,
3323                    IN OUT AFSCommResult **ResultCB)
3324 {
3325     AFSFileOpenResultCB *pResultCB = NULL;
3326     cm_scache_t *scp = NULL;
3327     cm_user_t   *sysUserp = NULL;
3328     cm_fid_t    Fid;
3329     cm_lock_data_t      *ldp = NULL;
3330     afs_uint32  code;
3331     cm_req_t    req;
3332     DWORD       status;
3333
3334     RDR_InitReq(&req, bWow64);
3335
3336     osi_Log4(afsd_logp, "RDR_OpenFileEntry File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3337               FileId.Cell, FileId.Volume,
3338               FileId.Vnode, FileId.Unique);
3339
3340     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
3341     if (!(*ResultCB)) {
3342         osi_Log0(afsd_logp, "RDR_OpenFileEntry out of memory");
3343         return;
3344     }
3345
3346     memset( *ResultCB,
3347             '\0',
3348             sizeof( AFSCommResult) + sizeof( AFSFileOpenResultCB));
3349
3350     pResultCB = (AFSFileOpenResultCB *)(*ResultCB)->ResultData;
3351
3352     /* Process the release */
3353     Fid.cell = FileId.Cell;
3354     Fid.volume = FileId.Volume;
3355     Fid.vnode = FileId.Vnode;
3356     Fid.unique = FileId.Unique;
3357     Fid.hash = FileId.Hash;
3358
3359     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3360     if (code) {
3361         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3362         (*ResultCB)->ResultStatus = status;
3363         osi_Log2(afsd_logp, "RDR_OpenFileEntry cm_GetSCache FID failure code=0x%x status=0x%x",
3364                   code, status);
3365         return;
3366     }
3367
3368     lock_ObtainWrite(&scp->rw);
3369     code = cm_SyncOp(scp, NULL, userp, &req, 0,
3370                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3371     if (code) {
3372         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3373         (*ResultCB)->ResultStatus = status;
3374         lock_ReleaseWrite(&scp->rw);
3375         cm_ReleaseSCache(scp);
3376         osi_Log3(afsd_logp, "RDR_OpenFileEntry cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
3377                  scp, code, status);
3378         return;
3379     }
3380
3381     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3382     lock_ReleaseWrite(&scp->rw);
3383
3384     sysUserp = RDR_GetLocalSystemUser();
3385
3386     /*
3387      * Skip the open check if the request is coming from the local system account.
3388      * The local system has no tokens and therefore any requests sent to a file
3389      * server will fail.  Unfortunately, there are special system processes that
3390      * perform actions on files and directories in preparation for memory mapping
3391      * executables.  If the open check fails, the real request from the user process
3392      * will never be issued.
3393      *
3394      * Permitting the file system to allow subsequent operations to proceed does
3395      * not compromise security.  All requests to obtain file data or directory
3396      * enumerations will subsequently fail if they are not submitted under the
3397      * context of a process for that have access to the necessary credentials.
3398      */
3399
3400     if ( userp == sysUserp)
3401     {
3402         osi_Log1(afsd_logp, "RDR_OpenFileEntry LOCAL_SYSTEM access check skipped scp=0x%p",
3403                  scp);
3404         pResultCB->GrantedAccess = OpenCB->DesiredAccess;
3405         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3406         code = 0;
3407     }
3408     else
3409     {
3410         int count = 0;
3411
3412         do {
3413             if (count++ > 0) {
3414                 Sleep(350);
3415                 osi_Log3(afsd_logp,
3416                          "RDR_OpenFileEntry repeating open check scp=0x%p userp=0x%p code=0x%x",
3417                          scp, userp, code);
3418             }
3419             code = cm_CheckNTOpen(scp, OpenCB->DesiredAccess, OpenCB->ShareAccess,
3420                                   OPEN_ALWAYS,
3421                                   OpenCB->ProcessId, OpenCB->Identifier,
3422                                   userp, &req, &ldp);
3423             if (code == 0)
3424                 code = RDR_CheckAccess(scp, userp, &req, OpenCB->DesiredAccess, &pResultCB->GrantedAccess);
3425
3426
3427             cm_CheckNTOpenDone(scp, userp, &req, &ldp);
3428         } while (count < 100 && (code == CM_ERROR_RETRY || code == CM_ERROR_WOULDBLOCK));
3429     }
3430
3431     /*
3432      * If we are restricting sharing, we should do so with a suitable
3433      * share lock.
3434      */
3435     if (code == 0 && scp->fileType == CM_SCACHETYPE_FILE && !(OpenCB->ShareAccess & FILE_SHARE_WRITE)) {
3436         cm_key_t key;
3437         LARGE_INTEGER LOffset, LLength;
3438         int sLockType;
3439
3440         LOffset.HighPart = SMB_FID_QLOCK_HIGH;
3441         LOffset.LowPart = SMB_FID_QLOCK_LOW;
3442         LLength.HighPart = 0;
3443         LLength.LowPart = SMB_FID_QLOCK_LENGTH;
3444
3445         /*
3446          * If we are not opening the file for writing, then we don't
3447          * try to get an exclusive lock.  No one else should be able to
3448          * get an exclusive lock on the file anyway, although someone
3449          * else can get a shared lock.
3450          */
3451         if ((OpenCB->ShareAccess & FILE_SHARE_READ) || !(OpenCB->DesiredAccess & AFS_ACCESS_WRITE))
3452         {
3453             sLockType = LOCKING_ANDX_SHARED_LOCK;
3454         } else {
3455             sLockType = 0;
3456         }
3457
3458         key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, OpenCB->Identifier);
3459
3460         lock_ObtainWrite(&scp->rw);
3461         code = cm_Lock(scp, sLockType, LOffset, LLength, key, 0, userp, &req, NULL);
3462         lock_ReleaseWrite(&scp->rw);
3463
3464         if (code) {
3465             code = CM_ERROR_SHARING_VIOLATION;
3466             pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3467         } else {
3468             if (sLockType == LOCKING_ANDX_SHARED_LOCK)
3469                 pResultCB->FileAccess = AFS_FILE_ACCESS_SHARED;
3470             else
3471                 pResultCB->FileAccess = AFS_FILE_ACCESS_EXCLUSIVE;
3472         }
3473     } else {
3474         pResultCB->FileAccess = AFS_FILE_ACCESS_NOLOCK;
3475     }
3476
3477     cm_ReleaseUser(sysUserp);
3478     if (code == 0 && bHoldFid)
3479         RDR_FlagScpInUse( scp, FALSE );
3480     cm_ReleaseSCache(scp);
3481
3482     if (code) {
3483         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3484         (*ResultCB)->ResultStatus = status;
3485         osi_Log2(afsd_logp, "RDR_OpenFileEntry FAILURE code=0x%x status=0x%x",
3486                   code, status);
3487     } else {
3488         (*ResultCB)->ResultStatus = 0;
3489         (*ResultCB)->ResultBufferLength = sizeof( AFSFileOpenResultCB);
3490         osi_Log0(afsd_logp, "RDR_OpenFileEntry SUCCESS");
3491     }
3492     return;
3493 }
3494
3495 void
3496 RDR_ReleaseFileAccess( IN cm_user_t *userp,
3497                        IN AFSFileID FileId,
3498                        IN AFSFileAccessReleaseCB *ReleaseFileCB,
3499                        IN BOOL bWow64,
3500                        IN DWORD ResultBufferLength,
3501                        IN OUT AFSCommResult **ResultCB)
3502 {
3503     cm_key_t key;
3504     unsigned int sLockType;
3505     LARGE_INTEGER LOffset, LLength;
3506     cm_scache_t *scp = NULL;
3507     cm_fid_t    Fid;
3508     afs_uint32  code;
3509     cm_req_t    req;
3510     DWORD       status;
3511
3512     RDR_InitReq(&req, bWow64);
3513
3514     osi_Log4(afsd_logp, "RDR_ReleaseFileAccess File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3515               FileId.Cell, FileId.Volume,
3516               FileId.Vnode, FileId.Unique);
3517
3518     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
3519     if (!(*ResultCB)) {
3520         osi_Log0(afsd_logp, "RDR_ReleaseFileAccess out of memory");
3521         return;
3522     }
3523
3524     memset( *ResultCB, '\0', sizeof( AFSCommResult));
3525
3526     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_NOLOCK)
3527         return;
3528
3529     /* Process the release */
3530     Fid.cell = FileId.Cell;
3531     Fid.volume = FileId.Volume;
3532     Fid.vnode = FileId.Vnode;
3533     Fid.unique = FileId.Unique;
3534     Fid.hash = FileId.Hash;
3535
3536     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3537     if (code) {
3538         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3539         (*ResultCB)->ResultStatus = status;
3540         osi_Log2(afsd_logp, "RDR_ReleaseFileAccess cm_GetSCache FID failure code=0x%x status=0x%x",
3541                   code, status);
3542         return;
3543     }
3544
3545     if (ReleaseFileCB->FileAccess == AFS_FILE_ACCESS_SHARED)
3546         sLockType = LOCKING_ANDX_SHARED_LOCK;
3547     else
3548         sLockType = 0;
3549
3550     key = cm_GenerateKey(CM_SESSION_IFS, SMB_FID_QLOCK_PID, ReleaseFileCB->Identifier);
3551
3552     LOffset.HighPart = SMB_FID_QLOCK_HIGH;
3553     LOffset.LowPart = SMB_FID_QLOCK_LOW;
3554     LLength.HighPart = 0;
3555     LLength.LowPart = SMB_FID_QLOCK_LENGTH;
3556
3557     lock_ObtainWrite(&scp->rw);
3558
3559     code = cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_LOCK);
3560     if (code == 0)
3561     {
3562         code = cm_Unlock(scp, sLockType, LOffset, LLength, key, 0, userp, &req);
3563
3564         cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_LOCK);
3565
3566         if (code == CM_ERROR_RANGE_NOT_LOCKED)
3567         {
3568             osi_Log3(afsd_logp, "RDR_ReleaseFileAccess Range Not Locked -- FileAccess 0x%x ProcessId 0x%x HandleId 0x%x",
3569                      ReleaseFileCB->FileAccess, ReleaseFileCB->ProcessId, ReleaseFileCB->Identifier);
3570         }
3571     }
3572
3573     lock_ReleaseWrite(&scp->rw);
3574
3575     osi_Log0(afsd_logp, "RDR_ReleaseFileAccessEntry SUCCESS");
3576 }
3577
3578 static const char *
3579 HexCheckSum(unsigned char * buf, int buflen, unsigned char * md5cksum)
3580 {
3581     int i, k;
3582     static char tr[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
3583
3584     if (buflen < 33)
3585         return "buffer length too small to HexCheckSum";
3586
3587     for (i=0;i<16;i++) {
3588         k = md5cksum[i];
3589
3590         buf[i*2] = tr[k / 16];
3591         buf[i*2+1] = tr[k % 16];
3592     }
3593     buf[32] = '\0';
3594
3595     return buf;
3596 }
3597
3598 /*
3599  * Extent requests from the file system are triggered when a file
3600  * page is not resident in the Windows cache.  The file system is
3601  * responsible for loading the page but cannot block the request
3602  * while doing so.  The AFS Redirector forwards the requests to
3603  * the AFS cache manager while indicating to Windows that the page
3604  * is not yet available.  A polling operation will then ensue with
3605  * the AFS Redirector issuing a RDR_RequestFileExtentsXXX call for
3606  * each poll attempt.  As each request is received and processed
3607  * by a separate worker thread in the service, this can lead to
3608  * contention by multiple threads attempting to claim the same
3609  * cm_buf_t objects.  Therefore, it is important that
3610  *
3611  *  (a) the service avoid processing more than one overlapping
3612  *      extent request at a time
3613  *  (b) background daemon processing be used to avoid blocking
3614  *      of ioctl threads
3615  *
3616  * Beginning with the 20091122 build of the redirector, the redirector
3617  * will not issue an additional RDR_RequestFileExtentsXXX call for
3618  * each poll request.  Instead, afsd_service is required to track
3619  * the requests and return them to the redirector or fail the
3620  * portions of the request that cannot be satisfied.
3621  *
3622  * The request processing returns any extents that can be returned
3623  * immediately to the redirector.  The rest of the requested range(s)
3624  * are queued as background operations using RDR_BkgFetch().
3625  */
3626
3627 /* do the background fetch. */
3628 afs_int32
3629 RDR_BkgFetch(cm_scache_t *scp, void *rockp, cm_user_t *userp, cm_req_t *reqp)
3630 {
3631     osi_hyper_t length;
3632     osi_hyper_t base;
3633     osi_hyper_t offset;
3634     osi_hyper_t end;
3635     osi_hyper_t fetched;
3636     osi_hyper_t tblocksize;
3637     afs_int32 code;
3638     int rwheld = 0;
3639     cm_buf_t *bufp = NULL;
3640     DWORD dwResultBufferLength;
3641     AFSSetFileExtentsCB *pResultCB;
3642     DWORD status;
3643     afs_uint32 count=0;
3644     AFSFileID FileId;
3645     int reportErrorToRedir = 0;
3646     int force_retry = 0;
3647
3648     FileId.Cell = scp->fid.cell;
3649     FileId.Volume = scp->fid.volume;
3650     FileId.Vnode = scp->fid.vnode;
3651     FileId.Unique = scp->fid.unique;
3652     FileId.Hash = scp->fid.hash;
3653
3654     fetched.LowPart = 0;
3655     fetched.HighPart = 0;
3656     tblocksize = ConvertLongToLargeInteger(cm_data.buf_blockSize);
3657     base = ((rock_BkgFetch_t *)rockp)->base;
3658     length = ((rock_BkgFetch_t *)rockp)->length;
3659     end = LargeIntegerAdd(base, length);
3660
3661     osi_Log5(afsd_logp, "Starting BKG Fetch scp 0x%p offset 0x%x:%x length 0x%x:%x",
3662              scp, base.HighPart, base.LowPart, length.HighPart, length.LowPart);
3663
3664     /*
3665      * Make sure we have a callback.
3666      * This is necessary so that we can return access denied
3667      * if a callback cannot be granted.
3668      */
3669     lock_ObtainWrite(&scp->rw);
3670     code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_READ,
3671                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3672     if (code) {
3673         lock_ReleaseWrite(&scp->rw);
3674         osi_Log2(afsd_logp, "RDR_BkgFetch cm_SyncOp failure scp=0x%p code=0x%x",
3675                  scp, code);
3676         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
3677         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3678         return code;
3679     }
3680     lock_ReleaseWrite(&scp->rw);
3681
3682     dwResultBufferLength = (DWORD)(sizeof( AFSSetFileExtentsCB) + sizeof( AFSFileExtentCB) * (length.QuadPart / cm_data.blockSize + 1));
3683     pResultCB = (AFSSetFileExtentsCB *)malloc( dwResultBufferLength );
3684     if (!pResultCB)
3685         return CM_ERROR_RETRY;
3686
3687     memset( pResultCB, '\0', dwResultBufferLength );
3688     pResultCB->FileId = FileId;
3689
3690     for ( code = 0, offset = base;
3691           code == 0 && LargeIntegerLessThan(offset, end);
3692           offset = LargeIntegerAdd(offset, tblocksize) )
3693     {
3694         int bBufRelease = TRUE;
3695
3696         if (rwheld) {
3697             lock_ReleaseWrite(&scp->rw);
3698             rwheld = 0;
3699         }
3700
3701         code = buf_Get(scp, &offset, reqp, 0, &bufp);
3702         if (code) {
3703             /*
3704              * any error from buf_Get() is non-fatal.
3705              * we need to re-queue this extent fetch.
3706              */
3707             force_retry = 1;
3708             break;
3709         }
3710
3711         if (!rwheld) {
3712             lock_ObtainWrite(&scp->rw);
3713             rwheld = 1;
3714         }
3715
3716         code = cm_GetBuffer(scp, bufp, NULL, userp, reqp);
3717         if (code == 0) {
3718             if (!(bufp->qFlags & CM_BUF_QREDIR)) {
3719 #ifdef VALIDATE_CHECK_SUM
3720 #ifdef ODS_DEBUG
3721                 char md5dbg[33];
3722                 char dbgstr[1024];
3723 #endif
3724 #endif
3725                 if (bufp->flags & CM_BUF_DIRTY)
3726                     cm_BufWrite(scp, &bufp->offset, cm_data.buf_blockSize, CM_BUF_WRITE_SCP_LOCKED, userp, reqp);
3727
3728                 lock_ObtainWrite(&buf_globalLock);
3729                 if (!(bufp->flags & CM_BUF_DIRTY) &&
3730                     bufp->cmFlags == 0 &&
3731                     !(bufp->qFlags & CM_BUF_QREDIR)) {
3732                     buf_InsertToRedirQueue(scp, bufp);
3733                     lock_ReleaseWrite(&buf_globalLock);
3734
3735 #ifdef VALIDATE_CHECK_SUM
3736                     buf_ComputeCheckSum(bufp);
3737 #endif
3738                     pResultCB->FileExtents[count].Flags = 0;
3739                     pResultCB->FileExtents[count].FileOffset.QuadPart = bufp->offset.QuadPart;
3740                     pResultCB->FileExtents[count].CacheOffset.QuadPart = bufp->datap - RDR_extentBaseAddress;
3741                     pResultCB->FileExtents[count].Length = cm_data.blockSize;
3742                     count++;
3743                     fetched = LargeIntegerAdd(fetched, tblocksize);
3744                     bBufRelease = FALSE;
3745
3746 #ifdef VALIDATE_CHECK_SUM
3747 #ifdef ODS_DEBUG
3748                     HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
3749                     snprintf( dbgstr, 1024,
3750                               "RDR_BkgFetch md5 %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
3751                               md5dbg,
3752                               scp->fid.volume, scp->fid.vnode, scp->fid.unique,
3753                               pResultCB->FileExtents[count].FileOffset.HighPart,
3754                               pResultCB->FileExtents[count].FileOffset.LowPart,
3755                               pResultCB->FileExtents[count].CacheOffset.HighPart,
3756                               pResultCB->FileExtents[count].CacheOffset.LowPart);
3757                     OutputDebugStringA( dbgstr);
3758 #endif
3759 #endif
3760                     osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3761                               bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3762                 } else {
3763                     lock_ReleaseWrite(&buf_globalLock);
3764                     if ((bufp->cmFlags != 0) || (bufp->flags & CM_BUF_DIRTY)) {
3765                         /* An I/O operation is already in progress */
3766                         force_retry = 1;
3767                         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",
3768                                   bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3769                     } else {
3770                         osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3771                                   bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3772                     }
3773                 }
3774             } else {
3775                 osi_Log4(afsd_logp, "RDR_BkgFetch Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
3776                           bufp, bufp->offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
3777             }
3778         } else {
3779             /*
3780              * depending on what the error from cm_GetBuffer is
3781              * it may or may not be fatal.  Only return fatal errors.
3782              * Re-queue a request for others.
3783              */
3784             osi_Log5(afsd_logp, "RDR_BkgFetch Extent2FS FAILURE bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x code 0x%x",
3785                       bufp, offset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize, code);
3786             switch (code) {
3787             case CM_ERROR_NOACCESS:
3788             case CM_ERROR_NOSUCHFILE:
3789             case CM_ERROR_NOSUCHPATH:
3790             case CM_ERROR_NOSUCHVOLUME:
3791             case CM_ERROR_NOSUCHCELL:
3792             case CM_ERROR_INVAL:
3793             case CM_ERROR_BADFD:
3794             case CM_ERROR_CLOCKSKEW:
3795             case RXKADNOAUTH:
3796             case CM_ERROR_QUOTA:
3797             case CM_ERROR_LOCK_CONFLICT:
3798             case EIO:
3799             case CM_ERROR_INVAL_NET_RESP:
3800             case CM_ERROR_UNKNOWN:
3801                 /*
3802                  * these are fatal errors.  deliver what we can
3803                  * and halt.
3804                  */
3805                 reportErrorToRedir = 1;
3806                 break;
3807             default:
3808                 /*
3809                  * non-fatal errors.  re-queue the exent
3810                  */
3811                 code = CM_ERROR_RETRY;
3812                 force_retry = 1;
3813             }
3814         }
3815
3816         if (bBufRelease)
3817             buf_Release(bufp);
3818     }
3819
3820     if (!rwheld) {
3821         lock_ObtainWrite(&scp->rw);
3822         rwheld = 1;
3823     }
3824
3825     /* wakeup anyone who is waiting */
3826     if (scp->flags & CM_SCACHEFLAG_WAITING) {
3827         osi_Log1(afsd_logp, "RDR Bkg Fetch Waking scp 0x%p", scp);
3828         osi_Wakeup((LONG_PTR) &scp->flags);
3829     }
3830     lock_ReleaseWrite(&scp->rw);
3831
3832     if (count > 0) {
3833         pResultCB->ExtentCount = count;
3834         RDR_SetFileExtents( pResultCB, dwResultBufferLength);
3835     }
3836     free(pResultCB);
3837
3838     if (reportErrorToRedir) {
3839         smb_MapNTError(cm_MapRPCError(code, reqp), &status, TRUE);
3840         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3841     }
3842
3843     osi_Log4(afsd_logp, "Ending BKG Fetch scp 0x%p code 0x%x fetched 0x%x:%x",
3844              scp, code, fetched.HighPart, fetched.LowPart);
3845
3846     return force_retry ? CM_ERROR_RETRY : code;
3847 }
3848
3849
3850 BOOL
3851 RDR_RequestFileExtentsAsync( IN cm_user_t *userp,
3852                              IN AFSFileID FileId,
3853                              IN AFSRequestExtentsCB *RequestExtentsCB,
3854                              IN BOOL bWow64,
3855                              IN OUT DWORD * ResultBufferLength,
3856                              IN OUT AFSSetFileExtentsCB **ResultCB)
3857 {
3858     AFSSetFileExtentsCB *pResultCB = NULL;
3859     DWORD Length;
3860     DWORD count;
3861     DWORD status;
3862     cm_scache_t *scp = NULL;
3863     cm_fid_t    Fid;
3864     cm_buf_t    *bufp;
3865     afs_uint32  code = 0;
3866     osi_hyper_t thyper;
3867     LARGE_INTEGER ByteOffset, BeginOffset, EndOffset, QueueOffset;
3868     afs_uint32  QueueLength;
3869     cm_req_t    req;
3870     BOOLEAN     bBufRelease = TRUE;
3871
3872     RDR_InitReq(&req, bWow64);
3873     req.flags |= CM_REQ_NORETRY;
3874
3875     osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
3876               FileId.Cell, FileId.Volume,
3877               FileId.Vnode, FileId.Unique);
3878     osi_Log4(afsd_logp, "... Flags 0x%x ByteOffset 0x%x:%x Length 0x%x",
3879              RequestExtentsCB->Flags,
3880              RequestExtentsCB->ByteOffset.HighPart, RequestExtentsCB->ByteOffset.LowPart,
3881              RequestExtentsCB->Length);
3882     Length = sizeof( AFSSetFileExtentsCB) + sizeof( AFSFileExtentCB) * (RequestExtentsCB->Length / cm_data.blockSize + 1);
3883
3884     pResultCB = *ResultCB = (AFSSetFileExtentsCB *)malloc( Length );
3885     if (*ResultCB == NULL) {
3886         *ResultBufferLength = 0;
3887         return FALSE;
3888     }
3889     *ResultBufferLength = Length;
3890
3891     memset( pResultCB, '\0', Length );
3892     pResultCB->FileId = FileId;
3893
3894     Fid.cell = FileId.Cell;
3895     Fid.volume = FileId.Volume;
3896     Fid.vnode = FileId.Vnode;
3897     Fid.unique = FileId.Unique;
3898     Fid.hash = FileId.Hash;
3899
3900     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
3901     if (code) {
3902         osi_Log1(afsd_logp, "RDR_RequestFileExtentsAsync cm_GetSCache FID failure code=0x%x",
3903                   code);
3904         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3905         return FALSE;
3906     }
3907
3908     /*
3909      * Make sure we have a callback.
3910      * This is necessary so that we can return access denied
3911      * if a callback cannot be granted.
3912      */
3913     lock_ObtainWrite(&scp->rw);
3914     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
3915                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3916     lock_ReleaseWrite(&scp->rw);
3917     if (code) {
3918         cm_ReleaseSCache(scp);
3919         osi_Log2(afsd_logp, "RDR_RequestFileExtentsAsync cm_SyncOp failure scp=0x%p code=0x%x",
3920                  scp, code);
3921         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3922         RDR_SetFileStatus( &scp->fid, &userp->authgroup, status);
3923         return FALSE;
3924     }
3925
3926     /* Allocate the extents from the buffer package */
3927     for ( count = 0,
3928           ByteOffset = BeginOffset = RequestExtentsCB->ByteOffset,
3929           EndOffset.QuadPart = ByteOffset.QuadPart + RequestExtentsCB->Length;
3930           code == 0 && ByteOffset.QuadPart < EndOffset.QuadPart;
3931           ByteOffset.QuadPart += cm_data.blockSize)
3932     {
3933         BOOL bHaveBuffer = FALSE;
3934
3935         QueueLength = 0;
3936         thyper.QuadPart = ByteOffset.QuadPart;
3937
3938         code = buf_Get(scp, &thyper, &req, 0,  &bufp);
3939         if (code == 0) {
3940             lock_ObtainMutex(&bufp->mx);
3941             bBufRelease = TRUE;
3942
3943             if (bufp->qFlags & CM_BUF_QREDIR) {
3944                 bHaveBuffer = TRUE;
3945             } else if (bufp->flags & CM_BUF_DIRTY) {
3946                 bHaveBuffer = FALSE;
3947 #if 0
3948                 code = buf_CleanAsyncLocked(scp, bufp, &req, 0, NULL);
3949                 switch (code) {
3950                 case 0:
3951                     bHaveBuffer = TRUE;
3952                     break;
3953                 case CM_ERROR_RETRY:
3954                     /* Couldn't flush it, obtain it asynchronously so we don't block the thread. */
3955                     bHaveBuffer = FALSE;
3956                     code = 0;
3957                     break;
3958                 default:
3959                     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
3960                     RDR_SetFileStatus(&FileId, &userp->authgroup, status);
3961                     bHaveBuffer = FALSE;
3962                     code = 0;
3963                 }
3964 #endif
3965             } else {
3966                 osi_hyper_t minLength;  /* effective end of file */
3967
3968                 lock_ObtainRead(&scp->rw);
3969                 bHaveBuffer = cm_HaveBuffer(scp, bufp, TRUE);
3970
3971                 if (LargeIntegerGreaterThan(scp->length, scp->serverLength))
3972                     minLength = scp->serverLength;
3973                 else
3974                     minLength = scp->length;
3975
3976                 if (LargeIntegerGreaterThanOrEqualTo(bufp->offset, minLength)) {
3977                     if (!bHaveBuffer) {
3978                         memset(bufp->datap, 0, cm_data.buf_blockSize);
3979                         bufp->dataVersion = scp->dataVersion;
3980                         bHaveBuffer = TRUE;
3981                     }
3982                     else if (bufp->dataVersion == CM_BUF_VERSION_BAD) {
3983                         bufp->dataVersion = scp->dataVersion;
3984                     }
3985                 }
3986                 else if ((RequestExtentsCB->Flags & AFS_EXTENT_FLAG_CLEAN) &&
3987                          ByteOffset.QuadPart <= bufp->offset.QuadPart &&
3988                          EndOffset.QuadPart >= bufp->offset.QuadPart + cm_data.blockSize)
3989                 {
3990                     memset(bufp->datap, 0, cm_data.blockSize);
3991                     bufp->dataVersion = scp->dataVersion;
3992                     buf_SetDirty(bufp, &req, 0, cm_data.blockSize, userp);
3993                     bHaveBuffer = TRUE;
3994                 }
3995                 lock_ReleaseRead(&scp->rw);
3996             }
3997
3998             /*
3999              * if this buffer is already up to date, skip it.
4000              */
4001             if (bHaveBuffer) {
4002                 if (ByteOffset.QuadPart == BeginOffset.QuadPart) {
4003                     BeginOffset.QuadPart += cm_data.blockSize;
4004                 } else {
4005                     QueueLength = (afs_uint32)(ByteOffset.QuadPart - BeginOffset.QuadPart);
4006                     QueueOffset = BeginOffset;
4007                     BeginOffset = ByteOffset;
4008                 }
4009
4010                 if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4011 #ifdef VALIDATE_CHECK_SUM
4012 #ifdef ODS_DEBUG
4013                     char md5dbg[33];
4014                     char dbgstr[1024];
4015 #endif
4016 #endif
4017                     lock_ObtainWrite(&buf_globalLock);
4018                     if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4019                         buf_InsertToRedirQueue(scp, bufp);
4020                         lock_ReleaseWrite(&buf_globalLock);
4021
4022 #ifdef VALIDATE_CHECK_SUM
4023                         buf_ComputeCheckSum(bufp);
4024 #endif
4025                         /* we already have the buffer, return it now */
4026                         pResultCB->FileExtents[count].Flags = 0;
4027                         pResultCB->FileExtents[count].FileOffset = ByteOffset;
4028                         pResultCB->FileExtents[count].CacheOffset.QuadPart = bufp->datap - RDR_extentBaseAddress;
4029                         pResultCB->FileExtents[count].Length = cm_data.blockSize;
4030                         count++;
4031
4032                         bBufRelease = FALSE;
4033
4034 #ifdef VALIDATE_CHECK_SUM
4035 #ifdef ODS_DEBUG
4036                         HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
4037                         snprintf( dbgstr, 1024,
4038                                   "RDR_RequestFileExtentsAsync md5 %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4039                                   md5dbg,
4040                                   scp->fid.volume, scp->fid.vnode, scp->fid.unique,
4041                                   pResultCB->FileExtents[count].FileOffset.HighPart,
4042                                   pResultCB->FileExtents[count].FileOffset.LowPart,
4043                                   pResultCB->FileExtents[count].CacheOffset.HighPart,
4044                                   pResultCB->FileExtents[count].CacheOffset.LowPart);
4045                         OutputDebugStringA( dbgstr);
4046 #endif
4047 #endif
4048                         osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync Extent2FS bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
4049                                  bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
4050                     } else {
4051                         lock_ReleaseWrite(&buf_globalLock);
4052                     }
4053                 } else {
4054                     if (bBufRelease) {
4055                         /*
4056                          * The service is not handing off the extent to the redirector in this pass.
4057                          * However, we know the buffer is in recent use so move the buffer to the
4058                          * front of the queue
4059                          */
4060                         lock_ObtainWrite(&buf_globalLock);
4061                         buf_MoveToHeadOfRedirQueue(scp, bufp);
4062                         lock_ReleaseWrite(&buf_globalLock);
4063
4064                         osi_Log4(afsd_logp, "RDR_RequestFileExtentsAsync Extent2FS Already held by Redirector bufp 0x%p foffset 0x%p coffset 0x%p len 0x%x",
4065                                  bufp, ByteOffset.QuadPart, bufp->datap - RDR_extentBaseAddress, cm_data.blockSize);
4066                     }
4067                 }
4068             }
4069             lock_ReleaseMutex(&bufp->mx);
4070             if (bBufRelease)
4071                 buf_Release(bufp);
4072
4073             if (QueueLength) {
4074                 rock_BkgFetch_t * rockp = malloc(sizeof(*rockp));
4075
4076                 if (rockp) {
4077                     req.flags &= ~CM_REQ_NORETRY;
4078                     rockp->base = QueueOffset;
4079                     rockp->length.LowPart = QueueLength;
4080                     rockp->length.HighPart = 0;
4081
4082                     cm_QueueBKGRequest(scp, RDR_BkgFetch, rockp, userp, &req);
4083                     osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
4084                               QueueOffset.HighPart, QueueOffset.LowPart, QueueLength);
4085                     req.flags |= CM_REQ_NORETRY;
4086                 } else {
4087                     code = ENOMEM;
4088                 }
4089             }
4090         } else {
4091             /* No error from buf_Get() can be fatal */
4092             osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync buf_Get FAILURE offset 0x%x:%x code 0x%x",
4093                      BeginOffset.HighPart, BeginOffset.LowPart, code);
4094         }
4095     }
4096
4097     if (BeginOffset.QuadPart != EndOffset.QuadPart) {
4098         afs_uint32 length = (afs_uint32)(EndOffset.QuadPart - BeginOffset.QuadPart);
4099         rock_BkgFetch_t * rockp = malloc(sizeof(*rockp));
4100
4101         if (rockp) {
4102             req.flags &= ~CM_REQ_NORETRY;
4103             rockp->base = BeginOffset;
4104             rockp->length.LowPart = length;
4105             rockp->length.HighPart = 0;
4106
4107             cm_QueueBKGRequest(scp, RDR_BkgFetch, rockp, userp, &req);
4108             osi_Log3(afsd_logp, "RDR_RequestFileExtentsAsync Queued a Background Fetch offset 0x%x:%x length 0x%x",
4109                      BeginOffset.HighPart, BeginOffset.LowPart, length);
4110         } else {
4111             code = ENOMEM;
4112         }
4113     }
4114     cm_ReleaseSCache(scp);
4115
4116     (*ResultCB)->ExtentCount = count;
4117     osi_Log1(afsd_logp, "RDR_RequestFileExtentsAsync replying with 0x%x extent records", count);
4118     return FALSE;
4119 }
4120
4121 /*
4122  * When processing an extent release the extents must be accepted back by
4123  * the service even if there is an error condition returned to the redirector.
4124  * For example, there may no longer be a callback present or the file may
4125  * have been deleted on the file server.  Regardless, the extents must be
4126  * put back into the pool.
4127  */
4128 void
4129 RDR_ReleaseFileExtents( IN cm_user_t *userp,
4130                         IN AFSFileID FileId,
4131                         IN AFSReleaseExtentsCB *ReleaseExtentsCB,
4132                         IN BOOL bWow64,
4133                         IN DWORD ResultBufferLength,
4134                         IN OUT AFSCommResult **ResultCB)
4135 {
4136     DWORD count;
4137     cm_scache_t *scp = NULL;
4138     cm_fid_t    Fid;
4139     cm_buf_t    *bufp;
4140     afs_uint32  code;
4141     osi_hyper_t thyper;
4142     cm_req_t    req;
4143     int         dirty = 0;
4144     int         released = 0;
4145     int         deleted = 0;
4146     DWORD       status;
4147     rock_BkgStore_t *rockp;
4148 #ifdef ODS_DEBUG
4149 #ifdef VALIDATE_CHECK_SUM
4150     char md5dbg[33], md5dbg2[33], md5dbg3[33];
4151 #endif
4152     char dbgstr[1024];
4153 #endif
4154
4155     RDR_InitReq(&req, bWow64);
4156
4157     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
4158               FileId.Cell, FileId.Volume,
4159               FileId.Vnode, FileId.Unique);
4160
4161     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
4162     if (!(*ResultCB))
4163         return;
4164
4165     memset( *ResultCB,
4166             '\0',
4167             sizeof( AFSCommResult));
4168
4169     /* Process the release */
4170     Fid.cell = FileId.Cell;
4171     Fid.volume = FileId.Volume;
4172     Fid.vnode = FileId.Vnode;
4173     Fid.unique = FileId.Unique;
4174     Fid.hash = FileId.Hash;
4175
4176     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
4177     if (code) {
4178         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4179         (*ResultCB)->ResultStatus = status;
4180         osi_Log2(afsd_logp, "RDR_ReleaseFileExtents cm_GetSCache FID failure code=0x%x status=0x%x",
4181                   code, status);
4182     }
4183
4184     deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
4185
4186     /*
4187      * We do not stop processing as a result of being unable to find the cm_scache object.
4188      * If this occurs something really bad has happened since the cm_scache object must have
4189      * been recycled while extents were held by the redirector.  However, we will be resilient
4190      * and carry on without it.
4191      *
4192      * If the file is known to be deleted, there is no point attempting to ask the
4193      * file server about it or update the attributes.
4194      */
4195     if (scp && ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart &&
4196         !deleted)
4197     {
4198         cm_attr_t setAttr;
4199
4200         memset(&setAttr, 0, sizeof(cm_attr_t));
4201         lock_ObtainWrite(&scp->rw);
4202         if (ReleaseExtentsCB->AllocationSize.QuadPart != scp->length.QuadPart) {
4203
4204             osi_Log4(afsd_logp, "RDR_ReleaseFileExtents new length fid vol 0x%x vno 0x%x length 0x%x:%x",
4205                       scp->fid.volume, scp->fid.vnode,
4206                       ReleaseExtentsCB->AllocationSize.HighPart,
4207                       ReleaseExtentsCB->AllocationSize.LowPart);
4208
4209             setAttr.mask |= CM_ATTRMASK_LENGTH;
4210             setAttr.length.LowPart = ReleaseExtentsCB->AllocationSize.LowPart;
4211             setAttr.length.HighPart = ReleaseExtentsCB->AllocationSize.HighPart;
4212         }
4213         lock_ReleaseWrite(&scp->rw);
4214         if (setAttr.mask)
4215             code = cm_SetAttr(scp, &setAttr, userp, &req);
4216     }
4217
4218     for ( count = 0; count < ReleaseExtentsCB->ExtentCount; count++) {
4219         AFSFileExtentCB * pExtent = &ReleaseExtentsCB->FileExtents[count];
4220
4221         thyper.QuadPart = pExtent->FileOffset.QuadPart;
4222
4223         bufp = buf_Find(&Fid, &thyper);
4224         if (bufp) {
4225             if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
4226                 if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4227                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4228                               Fid.volume, Fid.vnode,
4229                               pExtent->FileOffset.HighPart,
4230                               pExtent->FileOffset.LowPart);
4231                     osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; previously released",
4232                               pExtent->CacheOffset.HighPart,
4233                               pExtent->CacheOffset.LowPart);
4234                 } else {
4235                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4236                               Fid.volume, Fid.vnode,
4237                               pExtent->FileOffset.HighPart,
4238                               pExtent->FileOffset.LowPart);
4239                     osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; owned by redirector",
4240                               pExtent->CacheOffset.HighPart,
4241                               pExtent->CacheOffset.LowPart);
4242                 }
4243                 buf_Release(bufp);
4244                 continue;
4245             }
4246
4247             if (pExtent->Flags & AFS_EXTENT_FLAG_IN_USE) {
4248                 osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4249                           Fid.volume, Fid.vnode,
4250                           pExtent->FileOffset.HighPart,
4251                           pExtent->FileOffset.LowPart);
4252                 osi_Log2(afsd_logp, "... coffset 0x%x:%x IN_USE by file system",
4253                           pExtent->CacheOffset.HighPart,
4254                           pExtent->CacheOffset.LowPart);
4255
4256                 /* Move the buffer to the front of the queue */
4257                 lock_ObtainWrite(&buf_globalLock);
4258                 buf_MoveToHeadOfRedirQueue(scp, bufp);
4259                 lock_ReleaseWrite(&buf_globalLock);
4260                 buf_Release(bufp);
4261                 continue;
4262             }
4263
4264             if (bufp->datap - RDR_extentBaseAddress == pExtent->CacheOffset.QuadPart) {
4265                 if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4266                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents extent vol 0x%x vno 0x%x foffset 0x%x:%x not held by file system",
4267                              Fid.volume, Fid.vnode, pExtent->FileOffset.HighPart,
4268                              pExtent->FileOffset.LowPart);
4269                     osi_Log2(afsd_logp, "... coffset 0x%x:%x",
4270                              pExtent->CacheOffset.HighPart,
4271                              pExtent->CacheOffset.LowPart);
4272                 } else {
4273                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtents bufp 0x%p vno 0x%x foffset 0x%x:%x",
4274                               bufp, bufp->fid.vnode, pExtent->FileOffset.HighPart,
4275                               pExtent->FileOffset.LowPart);
4276                     osi_Log2(afsd_logp, "... coffset 0x%x:%x",
4277                              pExtent->CacheOffset.HighPart,
4278                              pExtent->CacheOffset.LowPart);
4279
4280                     if (pExtent->Flags || ReleaseExtentsCB->Flags) {
4281                         lock_ObtainMutex(&bufp->mx);
4282                         if ( (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_RELEASE) ||
4283                              (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
4284                         {
4285                             if (bufp->qFlags & CM_BUF_QREDIR) {
4286                                 lock_ObtainWrite(&buf_globalLock);
4287                                 if (bufp->qFlags & CM_BUF_QREDIR) {
4288                                     buf_RemoveFromRedirQueue(scp, bufp);
4289                                     buf_ReleaseLocked(bufp, TRUE);
4290                                 }
4291                                 lock_ReleaseWrite(&buf_globalLock);
4292                             }
4293 #ifdef ODS_DEBUG
4294                             snprintf( dbgstr, 1024,
4295                                       "RDR_ReleaseFileExtents releasing: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4296                                       Fid.volume, Fid.vnode, Fid.unique,
4297                                       pExtent->FileOffset.HighPart,
4298                                       pExtent->FileOffset.LowPart,
4299                                       pExtent->CacheOffset.HighPart,
4300                                       pExtent->CacheOffset.LowPart);
4301                             OutputDebugStringA( dbgstr);
4302 #endif
4303                             released++;
4304                         } else {
4305 #ifdef ODS_DEBUG
4306                             snprintf( dbgstr, 1024,
4307                                       "RDR_ReleaseFileExtents not releasing: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4308                                       Fid.volume, Fid.vnode, Fid.unique,
4309                                       pExtent->FileOffset.HighPart,
4310                                       pExtent->FileOffset.LowPart,
4311                                       pExtent->CacheOffset.HighPart,
4312                                       pExtent->CacheOffset.LowPart);
4313                             OutputDebugStringA( dbgstr);
4314 #endif
4315                             osi_Log4( afsd_logp, "RDR_ReleaseFileExtents not releasing vol 0x%x vno 0x%x foffset 0x%x:%x",
4316                                       Fid.volume, Fid.vnode,
4317                                       pExtent->FileOffset.HighPart,
4318                                       pExtent->FileOffset.LowPart);
4319                             osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4320                                       pExtent->CacheOffset.HighPart,
4321                                       pExtent->CacheOffset.LowPart);
4322                         }
4323
4324                         if ( (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
4325                              (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY) )
4326                         {
4327 #ifdef VALIDATE_CHECK_SUM
4328 #ifdef ODS_DEBUG
4329                             HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
4330 #endif
4331
4332                             /*
4333                              * if the saved checksum matches the checksum of the current state of the buffer
4334                              * then the buffer is the same as what was given to the kernel.
4335                              */
4336                             if ( buf_ValidateCheckSum(bufp) ) {
4337                                 buf_ComputeCheckSum(bufp);
4338
4339                                 if (pExtent->Flags & AFS_EXTENT_FLAG_MD5_SET)
4340                                 {
4341 #ifdef ODS_DEBUG
4342                                     HexCheckSum(md5dbg2, sizeof(md5dbg2), pExtent->MD5);
4343                                     HexCheckSum(md5dbg3, sizeof(md5dbg3), bufp->md5cksum);
4344 #endif
4345                                     if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
4346                                     {
4347 #ifdef ODS_DEBUG
4348                                         snprintf( dbgstr, 1024,
4349                                                   "RDR_ReleaseFileExtents dirty flag set but not dirty and user != kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4350                                                   md5dbg, md5dbg2,md5dbg3,
4351                                                   Fid.volume, Fid.vnode, Fid.unique,
4352                                                   pExtent->FileOffset.HighPart,
4353                                                   pExtent->FileOffset.LowPart,
4354                                                   pExtent->CacheOffset.HighPart,
4355                                                   pExtent->CacheOffset.LowPart);
4356                                         OutputDebugStringA( dbgstr);
4357 #endif
4358                                         osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set and checksums do not match! vol 0x%x vno 0x%x foffset 0x%x:%x",
4359                                                   Fid.volume, Fid.vnode,
4360                                                   pExtent->FileOffset.HighPart,
4361                                                   pExtent->FileOffset.LowPart);
4362                                         osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4363                                                   pExtent->CacheOffset.HighPart,
4364                                                   pExtent->CacheOffset.LowPart);
4365                                         buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4366                                         dirty++;
4367                                     } else {
4368 #ifdef ODS_DEBUG
4369                                         snprintf( dbgstr, 1024,
4370                                                   "RDR_ReleaseFileExtents dirty flag set but not dirty and user == kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4371                                                   md5dbg, md5dbg2, md5dbg3,
4372                                                   Fid.volume, Fid.vnode, Fid.unique,
4373                                                   pExtent->FileOffset.HighPart,
4374                                                   pExtent->FileOffset.LowPart,
4375                                                   pExtent->CacheOffset.HighPart,
4376                                                   pExtent->CacheOffset.LowPart);
4377                                         OutputDebugStringA( dbgstr);
4378 #endif
4379                                         osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
4380                                                   Fid.volume, Fid.vnode,
4381                                                   pExtent->FileOffset.HighPart,
4382                                                   pExtent->FileOffset.LowPart);
4383                                         osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4384                                                   pExtent->CacheOffset.HighPart,
4385                                                   pExtent->CacheOffset.LowPart);
4386                                     }
4387                                 } else {
4388 #ifdef ODS_DEBUG
4389                                         snprintf( dbgstr, 1024,
4390                                                   "RDR_ReleaseFileExtents dirty flag set but not dirty: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4391                                                   Fid.volume, Fid.vnode, Fid.unique,
4392                                                   pExtent->FileOffset.HighPart,
4393                                                   pExtent->FileOffset.LowPart,
4394                                                   pExtent->CacheOffset.HighPart,
4395                                                   pExtent->CacheOffset.LowPart);
4396                                         OutputDebugStringA( dbgstr);
4397 #endif
4398                                         osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
4399                                                   Fid.volume, Fid.vnode,
4400                                                   pExtent->FileOffset.HighPart,
4401                                                   pExtent->FileOffset.LowPart);
4402                                         osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4403                                                   pExtent->CacheOffset.HighPart,
4404                                                   pExtent->CacheOffset.LowPart);
4405                                 }
4406                             } else {
4407                                 buf_ComputeCheckSum(bufp);
4408 #ifdef ODS_DEBUG
4409                                 if (pExtent->Flags & AFS_EXTENT_FLAG_MD5_SET)
4410                                 {
4411                                     HexCheckSum(md5dbg3, sizeof(md5dbg3), bufp->md5cksum);
4412                                     if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
4413                                     {
4414                                         snprintf( dbgstr, 1024,
4415                                                   "RDR_ReleaseFileExtents dirty flag set and dirty and user != kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4416                                                   md5dbg, md5dbg2,md5dbg3,
4417                                                   Fid.volume, Fid.vnode, Fid.unique,
4418                                                   pExtent->FileOffset.HighPart,
4419                                                   pExtent->FileOffset.LowPart,
4420                                                   pExtent->CacheOffset.HighPart,
4421                                                   pExtent->CacheOffset.LowPart);
4422                                         OutputDebugStringA( dbgstr);
4423                                     } else {
4424                                         snprintf( dbgstr, 1024,
4425                                                   "RDR_ReleaseFileExtents dirty flag set and dirty and user == kernel: old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4426                                                   md5dbg, md5dbg2,md5dbg3,
4427                                                   Fid.volume, Fid.vnode, Fid.unique,
4428                                                   pExtent->FileOffset.HighPart,
4429                                                   pExtent->FileOffset.LowPart,
4430                                                   pExtent->CacheOffset.HighPart,
4431                                                   pExtent->CacheOffset.LowPart);
4432                                         OutputDebugStringA( dbgstr);
4433                                     }
4434                                 } else {
4435                                     snprintf( dbgstr, 1024,
4436                                               "RDR_ReleaseFileExtents dirty flag set: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4437                                               Fid.volume, Fid.vnode, Fid.unique,
4438                                               pExtent->FileOffset.HighPart,
4439                                               pExtent->FileOffset.LowPart,
4440                                               pExtent->CacheOffset.HighPart,
4441                                               pExtent->CacheOffset.LowPart);
4442                                     OutputDebugStringA( dbgstr);
4443                                 }
4444 #endif
4445                                 buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4446                                 dirty++;
4447                             }
4448 #else /* !VALIDATE_CHECK_SUM */
4449                             buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4450                             dirty++;
4451 #endif /* VALIDATE_CHECK_SUM */
4452                         }
4453 #ifdef VALIDATE_CHECK_SUM
4454                         else {
4455 #ifdef ODS_DEBUG
4456                             HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
4457 #endif
4458                             if ( !buf_ValidateCheckSum(bufp) ) {
4459                                 buf_ComputeCheckSum(bufp);
4460 #ifdef ODS_DEBUG
4461                                 HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
4462                                 snprintf( dbgstr, 1024,
4463                                           "RDR_ReleaseFileExtents dirty flag not set but dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4464                                           md5dbg, md5dbg3,
4465                                           Fid.volume, Fid.vnode, Fid.unique,
4466                                           pExtent->FileOffset.HighPart,
4467                                           pExtent->FileOffset.LowPart,
4468                                           pExtent->CacheOffset.HighPart,
4469                                           pExtent->CacheOffset.LowPart);
4470                                 OutputDebugStringA( dbgstr);
4471 #endif
4472                                 osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag not set but extent has changed vol 0x%x vno 0x%x foffset 0x%x:%x",
4473                                           Fid.volume, Fid.vnode,
4474                                           pExtent->FileOffset.HighPart,
4475                                           pExtent->FileOffset.LowPart);
4476                                 osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4477                                           pExtent->CacheOffset.HighPart,
4478                                           pExtent->CacheOffset.LowPart);
4479                                 buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4480                                 dirty++;
4481                             } else {
4482                                 buf_ComputeCheckSum(bufp);
4483 #ifdef ODS_DEBUG
4484                                 HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
4485                                 snprintf( dbgstr, 1024,
4486                                           "RDR_ReleaseFileExtents dirty flag not set: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4487                                           Fid.volume, Fid.vnode, Fid.unique,
4488                                           pExtent->FileOffset.HighPart,
4489                                           pExtent->FileOffset.LowPart,
4490                                           pExtent->CacheOffset.HighPart,
4491                                           pExtent->CacheOffset.LowPart);
4492                                 OutputDebugStringA( dbgstr);
4493 #endif
4494                                 osi_Log4( afsd_logp, "RDR_ReleaseFileExtents dirty flag not set: vol 0x%x vno 0x%x foffset 0x%x:%x",
4495                                           Fid.volume, Fid.vnode,
4496                                           pExtent->FileOffset.HighPart,
4497                                           pExtent->FileOffset.LowPart);
4498                                 osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4499                                           pExtent->CacheOffset.HighPart,
4500                                           pExtent->CacheOffset.LowPart);
4501                             }
4502                         }
4503 #endif /* VALIDATE_CHECK_SUM */
4504                         lock_ReleaseMutex(&bufp->mx);
4505                     }
4506                 }
4507             }
4508             else {
4509                 char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
4510                 cm_buf_t *wbp;
4511
4512                 for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
4513                     if (wbp->datap == datap)
4514                         break;
4515                 }
4516
4517 #ifdef ODS_DEBUG
4518                 snprintf( dbgstr, 1024,
4519                           "RDR_ReleaseFileExtents non-matching extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4520                           Fid.volume, Fid.vnode, Fid.unique,
4521                           pExtent->FileOffset.HighPart,
4522                           pExtent->FileOffset.LowPart,
4523                           pExtent->CacheOffset.HighPart,
4524                           pExtent->CacheOffset.LowPart);
4525                 OutputDebugStringA( dbgstr);
4526 #endif
4527                 osi_Log4( afsd_logp, "RDR_ReleaseFileExtents non-matching extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4528                           Fid.volume, Fid.vnode,
4529                           pExtent->FileOffset.HighPart,
4530                           pExtent->FileOffset.LowPart);
4531                 osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4532                           pExtent->CacheOffset.HighPart,
4533                           pExtent->CacheOffset.LowPart);
4534                 osi_Log5( afsd_logp, "... belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
4535                           wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
4536             }
4537             buf_Release(bufp);
4538         }
4539         else {
4540             char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
4541             cm_buf_t *wbp;
4542
4543             for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
4544                 if (wbp->datap == datap)
4545                     break;
4546             }
4547
4548 #ifdef ODS_DEBUG
4549             snprintf( dbgstr, 1024,
4550                       "RDR_ReleaseFileExtents unknown extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4551                       Fid.volume, Fid.vnode, Fid.unique,
4552                       pExtent->FileOffset.HighPart,
4553                       pExtent->FileOffset.LowPart,
4554                       pExtent->CacheOffset.HighPart,
4555                       pExtent->CacheOffset.LowPart);
4556             OutputDebugStringA( dbgstr);
4557 #endif
4558             osi_Log4( afsd_logp, "RDR_ReleaseFileExtents unknown extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4559                       Fid.volume, Fid.vnode,
4560                       pExtent->FileOffset.HighPart,
4561                       pExtent->FileOffset.LowPart);
4562             osi_Log2( afsd_logp, "... coffset 0x%x:%x",
4563                       pExtent->CacheOffset.HighPart,
4564                       pExtent->CacheOffset.LowPart);
4565             osi_Log5( afsd_logp, "... belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
4566                       wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
4567         }
4568     }
4569
4570     if (scp) {
4571         if (deleted) {
4572             code = 0;
4573         } else if (ReleaseExtentsCB->Flags & AFS_EXTENT_FLAG_FLUSH) {
4574             lock_ObtainWrite(&scp->rw);
4575             code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
4576                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4577             if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
4578                 code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
4579                                  CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4580             }
4581             lock_ReleaseWrite(&scp->rw);
4582             if (code == 0)
4583                 code = cm_FSync(scp, userp, &req, FALSE);
4584         }
4585         else if (dirty) {
4586             osi_hyper_t offset = {0,0};
4587             afs_uint32  length = 0;
4588             afs_uint32  rights = 0;
4589
4590             lock_ObtainWrite(&scp->rw);
4591             code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
4592                              CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4593             if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
4594                 code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
4595                                   CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4596             }
4597             lock_ReleaseWrite(&scp->rw);
4598             if (code == 0) {
4599                 /*
4600                  * there is at least one dirty extent on this file.  queue up background store
4601                  * requests for contiguous blocks
4602                  */
4603                 for ( count = 0; count < ReleaseExtentsCB->ExtentCount; count++) {
4604                     if (ReleaseExtentsCB->FileExtents[count].FileOffset.QuadPart == offset.QuadPart + length &&
4605                          length + cm_data.buf_blockSize <= cm_chunkSize)
4606                     {
4607                         length += cm_data.buf_blockSize;
4608                     } else {
4609                         if (!(offset.QuadPart == 0 && length == 0)) {
4610                             rockp = malloc(sizeof(*rockp));
4611                             if (rockp) {
4612                                 rockp->length = length;
4613                                 rockp->offset = offset;
4614
4615                                 cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
4616
4617                                 /* rock is freed by cm_BkgStore */
4618                             }
4619                         }
4620                         offset.QuadPart = ReleaseExtentsCB->FileExtents[count].FileOffset.QuadPart;
4621                         length = cm_data.buf_blockSize;
4622                     }
4623                 }
4624
4625                 /* Store whatever is left */
4626                 rockp = malloc(sizeof(*rockp));
4627                 if (rockp) {
4628                     rockp->length = length;
4629                     rockp->offset = offset;
4630
4631                     cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
4632
4633                     /* rock is freed by cm_BkgStore */
4634                 }
4635             }
4636         }
4637         cm_ReleaseSCache(scp);
4638     }
4639
4640     osi_Log5(afsd_logp, "RDR_ReleaseFileExtents File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x Released %d",
4641               FileId.Cell, FileId.Volume,
4642               FileId.Vnode, FileId.Unique, released);
4643     if (code && code != CM_ERROR_WOULDBLOCK) {
4644         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
4645         (*ResultCB)->ResultStatus = status;
4646         osi_Log2(afsd_logp, "RDR_ReleaseFileExtents FAILURE code=0x%x status=0x%x",
4647                   code, status);
4648     } else {
4649         (*ResultCB)->ResultStatus = 0;
4650         osi_Log0(afsd_logp, "RDR_ReleaseFileExtents SUCCESS");
4651     }
4652     (*ResultCB)->ResultBufferLength = 0;
4653
4654     return;
4655 }
4656
4657 DWORD
4658 RDR_ProcessReleaseFileExtentsResult( IN AFSReleaseFileExtentsResultCB *ReleaseFileExtentsResultCB,
4659                                      IN DWORD ResultBufferLength)
4660 {
4661     afs_uint32  code = 0;
4662     cm_req_t    req;
4663     osi_hyper_t thyper;
4664     cm_buf_t    *bufp;
4665     unsigned int fileno, extentno, total_extents = 0;
4666     AFSReleaseFileExtentsResultFileCB *pNextFileCB;
4667     rock_BkgStore_t *rockp;
4668 #ifdef ODS_DEBUG
4669 #ifdef VALIDATE_CHECK_SUM
4670     char md5dbg[33], md5dbg2[33], md5dbg3[33];
4671 #endif
4672     char dbgstr[1024];
4673 #endif
4674     RDR_InitReq(&req, FALSE);
4675
4676     for ( fileno = 0, pNextFileCB = &ReleaseFileExtentsResultCB->Files[0];
4677           fileno < ReleaseFileExtentsResultCB->FileCount;
4678           fileno++ ) {
4679         AFSReleaseFileExtentsResultFileCB *pFileCB = pNextFileCB;
4680         cm_user_t       *userp = NULL;
4681         cm_fid_t         Fid;
4682         cm_scache_t *    scp = NULL;
4683         int              dirty = 0;
4684         int              released = 0;
4685         int              deleted = 0;
4686         char * p;
4687
4688         userp = RDR_UserFromAuthGroup( &pFileCB->AuthGroup);
4689
4690         osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult %d.%d.%d.%d",
4691                   pFileCB->FileId.Cell, pFileCB->FileId.Volume,
4692                   pFileCB->FileId.Vnode, pFileCB->FileId.Unique);
4693
4694         /* Process the release */
4695         Fid.cell = pFileCB->FileId.Cell;
4696         Fid.volume = pFileCB->FileId.Volume;
4697         Fid.vnode = pFileCB->FileId.Vnode;
4698         Fid.unique = pFileCB->FileId.Unique;
4699         Fid.hash = pFileCB->FileId.Hash;
4700
4701         if (Fid.cell == 0) {
4702             osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult Invalid FID %d.%d.%d.%d",
4703                      Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
4704             code = CM_ERROR_INVAL;
4705             goto cleanup_file;
4706         }
4707
4708         code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
4709         if (code) {
4710             osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult cm_GetSCache FID failure code=0x%x",
4711                      code);
4712             /*
4713              * A failure to find the cm_scache object cannot prevent the service
4714              * from accepting the extents back from the redirector.
4715              */
4716         }
4717
4718         deleted = scp && (scp->flags & CM_SCACHEFLAG_DELETED);
4719
4720         /* if the scp was not found, do not perform the length check */
4721         if (scp && (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart)) {
4722             cm_attr_t setAttr;
4723
4724             memset(&setAttr, 0, sizeof(cm_attr_t));
4725             lock_ObtainWrite(&scp->rw);
4726             if (pFileCB->AllocationSize.QuadPart != scp->length.QuadPart) {
4727                 osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult length change vol 0x%x vno 0x%x length 0x%x:%x",
4728                           scp->fid.volume, scp->fid.vnode,
4729                           pFileCB->AllocationSize.HighPart,
4730                           pFileCB->AllocationSize.LowPart);
4731                 setAttr.mask |= CM_ATTRMASK_LENGTH;
4732                 setAttr.length.LowPart = pFileCB->AllocationSize.LowPart;
4733                 setAttr.length.HighPart = pFileCB->AllocationSize.HighPart;
4734             }
4735             lock_ReleaseWrite(&scp->rw);
4736             if (setAttr.mask)
4737                 code = cm_SetAttr(scp, &setAttr, userp, &req);
4738         }
4739
4740         for ( extentno = 0; extentno < pFileCB->ExtentCount; total_extents++, extentno++ ) {
4741             AFSFileExtentCB *pExtent = &pFileCB->FileExtents[extentno];
4742
4743             thyper.QuadPart = pExtent->FileOffset.QuadPart;
4744
4745             bufp = buf_Find(&Fid, &thyper);
4746             if (bufp) {
4747                 if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
4748                     if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4749                         osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4750                                  Fid.volume, Fid.vnode,
4751                                  pExtent->FileOffset.HighPart,
4752                                  pExtent->FileOffset.LowPart);
4753                         osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; previously released",
4754                                  pExtent->CacheOffset.HighPart,
4755                                  pExtent->CacheOffset.LowPart);
4756                     } else {
4757                         osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4758                                  Fid.volume, Fid.vnode,
4759                                  pExtent->FileOffset.HighPart,
4760                                  pExtent->FileOffset.LowPart);
4761                         osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; owned by redirector",
4762                                  pExtent->CacheOffset.HighPart,
4763                                  pExtent->CacheOffset.LowPart);
4764                     }
4765                     buf_Release(bufp);
4766                     continue;
4767                 }
4768
4769                 if (pExtent->Flags & AFS_EXTENT_FLAG_IN_USE) {
4770                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4771                               Fid.volume, Fid.vnode,
4772                               pExtent->FileOffset.HighPart,
4773                               pExtent->FileOffset.LowPart);
4774                     osi_Log2(afsd_logp, "... coffset 0x%x:%x IN_USE by file system",
4775                               pExtent->CacheOffset.HighPart,
4776                               pExtent->CacheOffset.LowPart);
4777
4778                     /* Move the buffer to the front of the queue */
4779                     lock_ObtainWrite(&buf_globalLock);
4780                     buf_MoveToHeadOfRedirQueue(scp, bufp);
4781                     lock_ReleaseWrite(&buf_globalLock);
4782                     buf_Release(bufp);
4783                     continue;
4784                 }
4785
4786                 if (bufp->datap - RDR_extentBaseAddress == pExtent->CacheOffset.QuadPart) {
4787                     if (!(bufp->qFlags & CM_BUF_QREDIR)) {
4788                         osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
4789                                  Fid.volume, Fid.vnode,
4790                                  pExtent->FileOffset.HighPart,
4791                                  pExtent->FileOffset.LowPart);
4792                         osi_Log2(afsd_logp, "... coffset 0x%x:%x not held by file system",
4793                                  pExtent->CacheOffset.HighPart,
4794                                  pExtent->CacheOffset.LowPart);
4795 #ifdef ODS_DEBUG
4796                         snprintf(dbgstr, 1024,
4797                                   "RDR_ProcessReleaseFileExtentsResult not held by redirector! flags 0x%x:%x vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4798                                   ReleaseFileExtentsResultCB->Flags, pExtent->Flags,
4799                                   Fid.volume, Fid.vnode, Fid.unique,
4800                                   pExtent->FileOffset.HighPart,
4801                                   pExtent->FileOffset.LowPart,
4802                                   pExtent->CacheOffset.HighPart,
4803                                   pExtent->CacheOffset.LowPart);
4804                         OutputDebugStringA( dbgstr);
4805 #endif
4806                     } else {
4807                         osi_Log5(afsd_logp, "RDR_ProcessReleaseFileExtentsResult bufp 0x%p foffset 0x%x:%x coffset 0x%x:%x",
4808                                  bufp, pExtent->FileOffset.HighPart, pExtent->FileOffset.LowPart,
4809                                  pExtent->CacheOffset.HighPart, pExtent->CacheOffset.LowPart);
4810
4811                         if (pExtent->Flags || ReleaseFileExtentsResultCB->Flags) {
4812                             lock_ObtainMutex(&bufp->mx);
4813                             if ( (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_RELEASE) ||
4814                                  (pExtent->Flags & AFS_EXTENT_FLAG_RELEASE) )
4815                             {
4816                                 if (bufp->qFlags & CM_BUF_QREDIR) {
4817                                     lock_ObtainWrite(&buf_globalLock);
4818                                     if (bufp->qFlags & CM_BUF_QREDIR) {
4819                                         buf_RemoveFromRedirQueue(scp, bufp);
4820                                         buf_ReleaseLocked(bufp, TRUE);
4821                                     }
4822                                     lock_ReleaseWrite(&buf_globalLock);
4823                                 }
4824
4825 #ifdef ODS_DEBUG
4826                                 snprintf(dbgstr, 1024,
4827                                           "RDR_ProcessReleaseFileExtentsResult extent released: vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4828                                           Fid.volume, Fid.vnode, Fid.unique,
4829                                           pExtent->FileOffset.HighPart,
4830                                           pExtent->FileOffset.LowPart,
4831                                           pExtent->CacheOffset.HighPart,
4832                                           pExtent->CacheOffset.LowPart);
4833                                 OutputDebugStringA( dbgstr);
4834 #endif
4835
4836                                 released++;
4837                             } else {
4838                                 osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult not releasing vol 0x%x vno 0x%x foffset 0x%x:%x",
4839                                          Fid.volume, Fid.vnode,
4840                                          pExtent->FileOffset.HighPart,
4841                                          pExtent->FileOffset.LowPart);
4842                                 osi_Log2(afsd_logp, "... coffset 0x%x:%x",
4843                                          pExtent->CacheOffset.HighPart,
4844                                          pExtent->CacheOffset.LowPart);
4845 #ifdef ODS_DEBUG
4846                                 snprintf(dbgstr, 1024,
4847                                           "RDR_ProcessReleaseFileExtentsResult not released! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4848                                           Fid.volume, Fid.vnode, Fid.unique,
4849                                           pExtent->FileOffset.HighPart,
4850                                           pExtent->FileOffset.LowPart,
4851                                           pExtent->CacheOffset.HighPart,
4852                                           pExtent->CacheOffset.LowPart);
4853                                 OutputDebugStringA( dbgstr);
4854 #endif
4855                             }
4856
4857                             if ((ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_DIRTY) ||
4858                                 (pExtent->Flags & AFS_EXTENT_FLAG_DIRTY))
4859                             {
4860 #ifdef VALIDATE_CHECK_SUM
4861                                 if ( buf_ValidateCheckSum(bufp) ) {
4862 #ifdef ODS_DEBUG
4863                                     HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
4864                                     if (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_MD5_SET)
4865                                         HexCheckSum(md5dbg2, sizeof(md5dbg2), pExtent->MD5);
4866 #endif
4867                                     buf_ComputeCheckSum(bufp);
4868 #ifdef ODS_DEBUG
4869                                     HexCheckSum(md5dbg3, sizeof(md5dbg), bufp->md5cksum);
4870 #endif
4871                                     if (ReleaseFileExtentsResultCB->Flags & AFS_EXTENT_FLAG_MD5_SET)
4872                                     {
4873                                         if (memcmp(bufp->md5cksum, pExtent->MD5, 16))
4874                                         {
4875 #ifdef ODS_DEBUG
4876                                             snprintf(dbgstr, 1024,
4877                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set and checksums do not match! user %s kernel %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4878                                                       md5dbg3, md5dbg2,
4879                                                       Fid.volume, Fid.vnode, Fid.unique,
4880                                                       pExtent->FileOffset.HighPart,
4881                                                       pExtent->FileOffset.LowPart,
4882                                                       pExtent->CacheOffset.HighPart,
4883                                                       pExtent->CacheOffset.LowPart);
4884                                             OutputDebugStringA( dbgstr);
4885 #endif
4886                                             osi_Log4(afsd_logp,
4887                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set and checksums do not match! vol 0x%x vno 0x%x foffset 0x%x:%x",
4888                                                       Fid.volume, Fid.vnode,
4889                                                       pExtent->FileOffset.HighPart,
4890                                                       pExtent->FileOffset.LowPart);
4891                                             osi_Log2(afsd_logp,
4892                                                       "... coffset 0x%x:%x",
4893                                                       pExtent->CacheOffset.HighPart,
4894                                                       pExtent->CacheOffset.LowPart);
4895
4896                                             if (!deleted) {
4897                                                 buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4898                                                 dirty++;
4899                                             }
4900                                         } else {
4901 #ifdef ODS_DEBUG
4902                                             snprintf(dbgstr, 1024,
4903                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set but extent has not changed! old %s kernel %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4904                                                       md5dbg, md5dbg2, md5dbg3,
4905                                                       Fid.volume, Fid.vnode, Fid.unique,
4906                                                       pExtent->FileOffset.HighPart,
4907                                                       pExtent->FileOffset.LowPart,
4908                                                       pExtent->CacheOffset.HighPart,
4909                                                       pExtent->CacheOffset.LowPart);
4910                                             OutputDebugStringA( dbgstr);
4911 #endif
4912                                             osi_Log4(afsd_logp,
4913                                                       "RDR_ProcessReleaseFileExtentsResult dirty flag set but extent has not changed vol 0x%x vno 0x%x foffset 0x%x:%x",
4914                                                       Fid.volume, Fid.vnode,
4915                                                       pExtent->FileOffset.HighPart,
4916                                                       pExtent->FileOffset.LowPart);
4917                                             osi_Log2(afsd_logp,
4918                                                       "... coffset 0x%x:%x",
4919                                                       pExtent->CacheOffset.HighPart,
4920                                                       pExtent->CacheOffset.LowPart);
4921                                         }
4922                                     }
4923                                 }
4924 #else /* !VALIDATE_CHECK_SUM */
4925                                 if (!deleted) {
4926                                     buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4927                                     dirty++;
4928                                 }
4929 #ifdef ODS_DEBUG
4930                                 snprintf(dbgstr, 1024,
4931                                           "RDR_ProcessReleaseFileExtentsResult dirty! vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4932                                           Fid.volume, Fid.vnode, Fid.unique,
4933                                           pExtent->FileOffset.HighPart,
4934                                           pExtent->FileOffset.LowPart,
4935                                           pExtent->CacheOffset.HighPart,
4936                                           pExtent->CacheOffset.LowPart);
4937                                 OutputDebugStringA( dbgstr);
4938 #endif
4939 #endif /* VALIDATE_CHECK_SUM */
4940                             }
4941 #ifdef VALIDATE_CHECK_SUM
4942                             else {
4943 #ifdef ODS_DEBUG
4944                                 HexCheckSum(md5dbg, sizeof(md5dbg), bufp->md5cksum);
4945 #endif
4946                                 if (!buf_ValidateCheckSum(bufp) ) {
4947                                     buf_ComputeCheckSum(bufp);
4948 #ifdef ODS_DEBUG
4949                                     HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
4950                                     snprintf(dbgstr, 1024,
4951                                              "RDR_ProcessReleaseFileExtentsResult dirty flag not set but dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4952                                              md5dbg, md5dbg3,
4953                                              Fid.volume, Fid.vnode, Fid.unique,
4954                                              pExtent->FileOffset.HighPart,
4955                                              pExtent->FileOffset.LowPart,
4956                                              pExtent->CacheOffset.HighPart,
4957                                              pExtent->CacheOffset.LowPart);
4958                                     OutputDebugStringA( dbgstr);
4959 #endif
4960                                     osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult dirty flag NOT set but extent has changed! vol 0x%x vno 0x%x foffset 0x%x:%x",
4961                                              Fid.volume, Fid.vnode,
4962                                              pExtent->FileOffset.HighPart,
4963                                              pExtent->FileOffset.LowPart);
4964                                     osi_Log2(afsd_logp, "... coffset 0x%x:%x",
4965                                              pExtent->CacheOffset.HighPart,
4966                                              pExtent->CacheOffset.LowPart);
4967
4968                                     if (!deleted) {
4969                                         buf_SetDirty(bufp, &req, pExtent->DirtyOffset, pExtent->DirtyLength, userp);
4970                                         dirty++;
4971                                     }
4972                                 } else {
4973                                     buf_ComputeCheckSum(bufp);
4974 #ifdef ODS_DEBUG
4975                                     HexCheckSum(md5dbg3, sizeof(md5dbg2), bufp->md5cksum);
4976                                     snprintf(dbgstr, 1024,
4977                                              "RDR_ProcessReleaseFileExtentsResult dirty flag not set and not dirty! old %s new %s vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
4978                                              md5dbg, md5dbg3,
4979                                              Fid.volume, Fid.vnode, Fid.unique,
4980                                              pExtent->FileOffset.HighPart,
4981                                              pExtent->FileOffset.LowPart,
4982                                              pExtent->CacheOffset.HighPart,
4983                                              pExtent->CacheOffset.LowPart);
4984                                     OutputDebugStringA( dbgstr);
4985 #endif
4986                                 }
4987                             }
4988 #endif /* VALIDATE_CHECK_SUM */
4989                             lock_ReleaseMutex(&bufp->mx);
4990                         }
4991                     }
4992                 } else {
4993                     /* CacheOffset doesn't match bufp->datap */
4994                     char * datap = RDR_extentBaseAddress + pExtent->CacheOffset.QuadPart;
4995                     cm_buf_t *wbp;
4996
4997                     for (wbp = cm_data.buf_allp; wbp; wbp = wbp->allp) {
4998                         if (wbp->datap == datap)
4999                             break;
5000                     }
5001
5002 #ifdef ODS_DEBUG
5003                     snprintf(dbgstr, 1024,
5004                              "RDR_ProcessReleaseFileExtentsResult non-matching extent vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x flags 0x%x\n",
5005                              Fid.volume, Fid.vnode, Fid.unique,
5006                              pExtent->FileOffset.HighPart,
5007                              pExtent->FileOffset.LowPart,
5008                              pExtent->CacheOffset.HighPart,
5009                              pExtent->CacheOffset.LowPart,
5010                              pExtent->Flags);
5011                     OutputDebugStringA( dbgstr);
5012 #endif
5013                     osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult non-matching extent vol 0x%x vno 0x%x foffset 0x%x:%x",
5014                              Fid.volume, Fid.vnode,
5015                              pExtent->FileOffset.HighPart,
5016                              pExtent->FileOffset.LowPart);
5017                     osi_Log3(afsd_logp, "... coffset 0x%x:%x flags 0x%x",
5018                              pExtent->CacheOffset.HighPart,
5019                              pExtent->CacheOffset.LowPart,
5020                              pExtent->Flags);
5021                     if (wbp)
5022                         osi_Log5(afsd_logp, "... coffset belongs to bp 0x%p vol 0x%x vno 0x%x foffset 0x%x:%x",
5023                                  wbp, wbp->fid.volume, wbp->fid.vnode, wbp->offset.HighPart, wbp->offset.LowPart);
5024                     else
5025                         osi_Log0(afsd_logp, "... coffset cannot be found");
5026                 }
5027                 buf_Release(bufp);
5028             } else {
5029                 if (pExtent->Flags & AFS_EXTENT_FLAG_UNKNOWN) {
5030                     osi_Log4(afsd_logp, "RDR_ReleaseFileExtentsResult extent vol 0x%x vno 0x%x foffset 0x%x:%x",
5031                              Fid.volume, Fid.vnode, pExtent->FileOffset.HighPart,
5032                              pExtent->FileOffset.LowPart);
5033                     osi_Log2(afsd_logp, "... coffset 0x%x:%x UNKNOWN to redirector; cm_buf not found -- recycled?",
5034                              pExtent->CacheOffset.HighPart,
5035                              pExtent->CacheOffset.LowPart);
5036
5037                     continue;
5038                 }
5039
5040 #ifdef ODS_DEBUG
5041                 snprintf(dbgstr, 1024,
5042                          "RDR_ProcessReleaseFileExtentsResult buf not found vol 0x%x vno 0x%x uniq 0x%x foffset 0x%x:%x coffset 0x%x:%x\n",
5043                          Fid.volume, Fid.vnode, Fid.unique,
5044                          pExtent->FileOffset.HighPart,
5045                          pExtent->FileOffset.LowPart,
5046                          pExtent->CacheOffset.HighPart,
5047                          pExtent->CacheOffset.LowPart);
5048                 OutputDebugStringA( dbgstr);
5049 #endif
5050                 osi_Log4(afsd_logp, "RDR_ProcessReleaseFileExtentsResult buf not found vol 0x%x vno 0x%x foffset 0x%x:%x",
5051                          Fid.volume, Fid.vnode,
5052                          pExtent->FileOffset.HighPart,
5053                          pExtent->FileOffset.LowPart);
5054                 osi_Log2(afsd_logp, "... coffset 0x%x:%x",
5055                          pExtent->CacheOffset.HighPart,
5056                          pExtent->CacheOffset.LowPart);
5057             }
5058         }
5059
5060         if (scp && dirty) {
5061             osi_hyper_t offset = {0,0};
5062             afs_uint32  length = 0;
5063
5064             /*
5065              * there is at least one dirty extent on this file.  queue up background store
5066              * requests for contiguous blocks
5067              */
5068             for ( extentno = 0; extentno < pFileCB->ExtentCount; extentno++ ) {
5069                 AFSFileExtentCB *pExtent = &pFileCB->FileExtents[extentno];
5070                 if (pExtent->FileOffset.QuadPart == offset.QuadPart + length &&
5071                      length < cm_chunkSize) {
5072                     length += cm_data.buf_blockSize;
5073                 } else {
5074                     if (!(offset.QuadPart == 0 && length == 0)) {
5075                         rockp = malloc(sizeof(*rockp));
5076                         if (rockp) {
5077                             rockp->offset = offset;
5078                             rockp->length = length;
5079
5080                             cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
5081                         } else {
5082                             code = ENOMEM;
5083                         }
5084                     }
5085                     offset.QuadPart = pExtent->FileOffset.QuadPart;
5086                     length = cm_data.buf_blockSize;
5087                 }
5088             }
5089
5090             /* Background store the rest */
5091             rockp = malloc(sizeof(*rockp));
5092             if (rockp) {
5093                 rockp->offset = offset;
5094                 rockp->length = length;
5095
5096                 cm_QueueBKGRequest(scp, cm_BkgStore, rockp, userp, &req);
5097             } else {
5098                 code = ENOMEM;
5099             }
5100         }
5101
5102         osi_Log5(afsd_logp, "RDR_ProcessReleaseFileExtentsResult File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x Released %d",
5103                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique, released);
5104
5105       cleanup_file:
5106         if (userp)
5107             cm_ReleaseUser(userp);
5108         if (scp)
5109             cm_ReleaseSCache(scp);
5110
5111         p = (char *)pFileCB;
5112         p += sizeof(AFSReleaseFileExtentsResultFileCB);
5113         p += sizeof(AFSFileExtentCB) * (pFileCB->ExtentCount - 1);
5114         pNextFileCB = (AFSReleaseFileExtentsResultFileCB *)p;
5115     }
5116
5117     if (total_extents == 0) {
5118         osi_Log0(afsd_logp, "RDR_ProcessReleaseFileExtentsResult is empty");
5119         code = CM_ERROR_RETRY;
5120     }
5121
5122     if (code)
5123         osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult FAILURE code=0x%x", code);
5124     else
5125         osi_Log1(afsd_logp, "RDR_ProcessReleaseFileExtentsResult DONE code=0x%x", code);
5126
5127     return code;
5128 }
5129
5130 DWORD
5131 RDR_ReleaseFailedSetFileExtents( IN cm_user_t *userp,
5132                                  IN AFSSetFileExtentsCB *SetFileExtentsResultCB,
5133                                  IN DWORD ResultBufferLength)
5134 {
5135     afs_uint32  code = 0;
5136     cm_req_t    req;
5137     unsigned int extentno;
5138     cm_fid_t         Fid;
5139     cm_scache_t *    scp = NULL;
5140     int              dirty = 0;
5141
5142     RDR_InitReq(&req, FALSE);
5143
5144     osi_Log4(afsd_logp, "RDR_ReleaseFailedSetFileExtents %d.%d.%d.%d",
5145               SetFileExtentsResultCB->FileId.Cell, SetFileExtentsResultCB->FileId.Volume,
5146               SetFileExtentsResultCB->FileId.Vnode, SetFileExtentsResultCB->FileId.Unique);
5147
5148     /* Process the release */
5149     Fid.cell = SetFileExtentsResultCB->FileId.Cell;
5150     Fid.volume = SetFileExtentsResultCB->FileId.Volume;
5151     Fid.vnode = SetFileExtentsResultCB->FileId.Vnode;
5152     Fid.unique = SetFileExtentsResultCB->FileId.Unique;
5153     Fid.hash = SetFileExtentsResultCB->FileId.Hash;
5154
5155     if (Fid.cell == 0) {
5156         osi_Log4(afsd_logp, "RDR_ReleaseFailedSetFile Invalid FID %d.%d.%d.%d",
5157                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
5158         code = CM_ERROR_INVAL;
5159         goto cleanup_file;
5160     }
5161
5162     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
5163     if (code) {
5164         osi_Log1(afsd_logp, "RDR_ReleaseFailedSetFileExtents cm_GetSCache FID failure code=0x%x",
5165                   code);
5166         /* Failure to find the cm_scache object cannot block return of the extents */
5167     }
5168
5169     for ( extentno = 0; extentno < SetFileExtentsResultCB->ExtentCount; extentno++ ) {
5170         osi_hyper_t thyper;
5171         cm_buf_t    *bufp;
5172         AFSFileExtentCB *pExtent = &SetFileExtentsResultCB->FileExtents[extentno];
5173
5174         thyper.QuadPart = pExtent->FileOffset.QuadPart;
5175
5176         bufp = buf_Find(&Fid, &thyper);
5177         if (bufp) {
5178             osi_Log5(afsd_logp, "RDR_ReleaseFailedSetFileExtents bufp 0x%p foffset 0x%x:%x coffset 0x%x:%x",
5179                       bufp, pExtent->FileOffset.HighPart, pExtent->FileOffset.LowPart,
5180                       pExtent->CacheOffset.HighPart, pExtent->CacheOffset.LowPart);
5181
5182             lock_ObtainMutex(&bufp->mx);
5183             if (bufp->qFlags & CM_BUF_QREDIR) {
5184                 lock_ObtainWrite(&buf_globalLock);
5185                 if (bufp->qFlags & CM_BUF_QREDIR) {
5186                     buf_RemoveFromRedirQueue(scp, bufp);
5187                     buf_ReleaseLocked(bufp, TRUE);
5188                 }
5189                 lock_ReleaseWrite(&buf_globalLock);
5190             }
5191             lock_ReleaseMutex(&bufp->mx);
5192             buf_Release(bufp);
5193         }
5194     }
5195
5196   cleanup_file:
5197     if (userp)
5198         cm_ReleaseUser(userp);
5199     if (scp)
5200         cm_ReleaseSCache(scp);
5201
5202     osi_Log1(afsd_logp, "RDR_ReleaseFailedSetFileExtents DONE code=0x%x", code);
5203     return code;
5204 }
5205
5206 void
5207 RDR_PioctlOpen( IN cm_user_t *userp,
5208                 IN AFSFileID  ParentId,
5209                 IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
5210                 IN BOOL bWow64,
5211                 IN DWORD ResultBufferLength,
5212                 IN OUT AFSCommResult **ResultCB)
5213 {
5214     cm_fid_t    ParentFid;
5215     cm_fid_t    RootFid;
5216     cm_req_t    req;
5217
5218     RDR_InitReq(&req, bWow64);
5219
5220     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
5221     if (!(*ResultCB))
5222         return;
5223
5224     memset( *ResultCB,
5225             '\0',
5226             sizeof( AFSCommResult));
5227
5228     /* Get the active directory */
5229     ParentFid.cell = ParentId.Cell;
5230     ParentFid.volume = ParentId.Volume;
5231     ParentFid.vnode = ParentId.Vnode;
5232     ParentFid.unique = ParentId.Unique;
5233     ParentFid.hash = ParentId.Hash;
5234
5235     /* Get the root directory */
5236     RootFid.cell = pPioctlCB->RootId.Cell;
5237     RootFid.volume = pPioctlCB->RootId.Volume;
5238     RootFid.vnode = pPioctlCB->RootId.Vnode;
5239     RootFid.unique = pPioctlCB->RootId.Unique;
5240     RootFid.hash = pPioctlCB->RootId.Hash;
5241
5242     /* Create the pioctl index */
5243     RDR_SetupIoctl(pPioctlCB->RequestId, &ParentFid, &RootFid, userp, &req);
5244
5245     return;
5246 }
5247
5248
5249 void
5250 RDR_PioctlClose( IN cm_user_t *userp,
5251                  IN AFSFileID  ParentId,
5252                  IN AFSPIOCtlOpenCloseRequestCB *pPioctlCB,
5253                  IN BOOL bWow64,
5254                  IN DWORD ResultBufferLength,
5255                  IN OUT AFSCommResult **ResultCB)
5256 {
5257     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
5258     if (!(*ResultCB))
5259         return;
5260
5261     memset( *ResultCB,
5262             '\0',
5263             sizeof( AFSCommResult));
5264
5265     /* Cleanup the pioctl index */
5266     RDR_CleanupIoctl(pPioctlCB->RequestId);
5267
5268     return;
5269 }
5270
5271
5272 void
5273 RDR_PioctlWrite( IN cm_user_t *userp,
5274                  IN AFSFileID  ParentId,
5275                  IN AFSPIOCtlIORequestCB *pPioctlCB,
5276                  IN BOOL bWow64,
5277                  IN DWORD ResultBufferLength,
5278                  IN OUT AFSCommResult **ResultCB)
5279 {
5280     AFSPIOCtlIOResultCB *pResultCB;
5281     cm_scache_t *dscp = NULL;
5282     afs_uint32  code;
5283     cm_req_t    req;
5284     DWORD       status;
5285
5286     RDR_InitReq(&req, bWow64);
5287
5288     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
5289     if (!(*ResultCB))
5290         return;
5291
5292     memset( *ResultCB,
5293             '\0',
5294             sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
5295
5296     pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
5297
5298     code = RDR_IoctlWrite(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer);
5299     if (code) {
5300         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5301         (*ResultCB)->ResultStatus = status;
5302         return;
5303     }
5304
5305     pResultCB->BytesProcessed = pPioctlCB->BufferLength;
5306     (*ResultCB)->ResultBufferLength = sizeof( AFSPIOCtlIOResultCB);
5307 }
5308
5309 void
5310 RDR_PioctlRead( IN cm_user_t *userp,
5311                 IN AFSFileID  ParentId,
5312                 IN AFSPIOCtlIORequestCB *pPioctlCB,
5313                 IN BOOL bWow64,
5314                 IN BOOL bIsLocalSystem,
5315                 IN DWORD ResultBufferLength,
5316                 IN OUT AFSCommResult **ResultCB)
5317 {
5318     AFSPIOCtlIOResultCB *pResultCB;
5319     cm_scache_t *dscp = NULL;
5320     afs_uint32  code;
5321     cm_req_t    req;
5322     DWORD       status;
5323     afs_uint32  pflags = (bIsLocalSystem ? AFSCALL_FLAG_LOCAL_SYSTEM : 0);
5324
5325     RDR_InitReq(&req, bWow64);
5326
5327     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
5328     if (!(*ResultCB))
5329         return;
5330
5331     memset( *ResultCB,
5332             '\0',
5333             sizeof( AFSCommResult) + sizeof(AFSPIOCtlIOResultCB));
5334
5335     pResultCB = (AFSPIOCtlIOResultCB *)(*ResultCB)->ResultData;
5336
5337     code = RDR_IoctlRead(userp, pPioctlCB->RequestId, pPioctlCB->BufferLength, pPioctlCB->MappedBuffer,
5338                          &pResultCB->BytesProcessed, pflags);
5339     if (code) {
5340         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5341         (*ResultCB)->ResultStatus = status;
5342         return;
5343     }
5344
5345     (*ResultCB)->ResultBufferLength = sizeof( AFSPIOCtlIOResultCB);
5346 }
5347
5348 void
5349 RDR_ByteRangeLockSync( IN cm_user_t     *userp,
5350                        IN AFSFileID     FileId,
5351                        IN AFSByteRangeLockRequestCB *pBRLRequestCB,
5352                        IN BOOL bWow64,
5353                        IN DWORD ResultBufferLength,
5354                        IN OUT AFSCommResult **ResultCB)
5355 {
5356     AFSByteRangeLockResultCB *pResultCB = NULL;
5357     LARGE_INTEGER ProcessId;
5358     DWORD       Length;
5359     cm_scache_t *scp = NULL;
5360     cm_fid_t    Fid;
5361     afs_uint32  code;
5362     cm_req_t    req;
5363     cm_key_t    key;
5364     DWORD       i;
5365     DWORD       status;
5366
5367     ProcessId.QuadPart = pBRLRequestCB->ProcessId;
5368
5369     RDR_InitReq(&req, bWow64);
5370
5371     osi_Log4(afsd_logp, "RDR_ByteRangeLockSync File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
5372               FileId.Cell, FileId.Volume,
5373               FileId.Vnode, FileId.Unique);
5374     osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
5375              ProcessId.HighPart, ProcessId.LowPart);
5376
5377     Length = sizeof( AFSByteRangeLockResultCB) + ((pBRLRequestCB->Count - 1) * sizeof(AFSByteRangeLockResult));
5378     if (Length > ResultBufferLength) {
5379         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult));
5380         if (!(*ResultCB))
5381             return;
5382         memset( *ResultCB, 0, sizeof(AFSCommResult));
5383         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
5384         return;
5385     }
5386
5387     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
5388     if (!(*ResultCB))
5389         return;
5390     memset( *ResultCB, '\0', Length + sizeof( AFSCommResult) );
5391     (*ResultCB)->ResultBufferLength = Length;
5392
5393     pResultCB = (AFSByteRangeLockResultCB *)(*ResultCB)->ResultData;
5394     pResultCB->FileId = FileId;
5395     pResultCB->Count = pBRLRequestCB->Count;
5396
5397     /* Allocate the extents from the buffer package */
5398     Fid.cell = FileId.Cell;
5399     Fid.volume = FileId.Volume;
5400     Fid.vnode = FileId.Vnode;
5401     Fid.unique = FileId.Unique;
5402     Fid.hash = FileId.Hash;
5403
5404     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
5405     if (code) {
5406         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5407         (*ResultCB)->ResultStatus = status;
5408         (*ResultCB)->ResultBufferLength = 0;
5409         osi_Log2(afsd_logp, "RDR_ByteRangeLockSync cm_GetSCache FID failure code=0x%x status=0x%x",
5410                   code, status);
5411         return;
5412     }
5413
5414     lock_ObtainWrite(&scp->rw);
5415
5416     /* start by looking up the file's end */
5417     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5418                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5419     if (code) {
5420         lock_ReleaseWrite(&scp->rw);
5421         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5422         (*ResultCB)->ResultStatus = status;
5423         (*ResultCB)->ResultBufferLength = 0;
5424         osi_Log3(afsd_logp, "RDR_ByteRangeLockSync cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
5425                  scp, code, status);
5426         return;
5427     }
5428
5429     /* the scp is now locked and current */
5430     key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
5431
5432     for ( i=0; i<pBRLRequestCB->Count; i++ ) {
5433         pResultCB->Result[i].LockType = pBRLRequestCB->Request[i].LockType;
5434         pResultCB->Result[i].Offset = pBRLRequestCB->Request[i].Offset;
5435         pResultCB->Result[i].Length = pBRLRequestCB->Request[i].Length;
5436
5437         code = cm_Lock(scp,
5438                        pBRLRequestCB->Request[i].LockType == AFS_BYTE_RANGE_LOCK_TYPE_SHARED,
5439                        pBRLRequestCB->Request[i].Offset,
5440                        pBRLRequestCB->Request[i].Length,
5441                        key, 0, userp, &req, NULL);
5442
5443         if (code) {
5444             osi_Log4(afsd_logp, "RDR_ByteRangeLockSync FAILURE code 0x%x type 0x%u offset 0x%x:%x",
5445                      code,
5446                      pBRLRequestCB->Request[i].LockType,
5447                      pBRLRequestCB->Request[i].Offset.HighPart,
5448                      pBRLRequestCB->Request[i].Offset.LowPart);
5449             osi_Log2(afsd_logp, "... length 0x%x:%x",
5450                      pBRLRequestCB->Request[i].Length.HighPart,
5451                      pBRLRequestCB->Request[i].Length.LowPart);
5452         }
5453
5454         switch (code) {
5455         case 0:
5456             pResultCB->Result[i].Status = 0;
5457             break;
5458         case CM_ERROR_WOULDBLOCK:
5459             pResultCB->Result[i].Status = STATUS_FILE_LOCK_CONFLICT;
5460             break;
5461         default:
5462             pResultCB->Result[i].Status = STATUS_LOCK_NOT_GRANTED;
5463         }
5464     }
5465
5466     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5467     lock_ReleaseWrite(&scp->rw);
5468     cm_ReleaseSCache(scp);
5469
5470     (*ResultCB)->ResultStatus = 0;
5471     osi_Log0(afsd_logp, "RDR_ByteRangeLockSync SUCCESS");
5472     return;
5473 }
5474
5475 void
5476 RDR_ByteRangeUnlock( IN cm_user_t     *userp,
5477                      IN AFSFileID     FileId,
5478                      IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
5479                      IN BOOL bWow64,
5480                      IN DWORD ResultBufferLength,
5481                      IN OUT AFSCommResult **ResultCB)
5482 {
5483     AFSByteRangeUnlockResultCB *pResultCB = NULL;
5484     LARGE_INTEGER ProcessId;
5485     DWORD       Length;
5486     cm_scache_t *scp = NULL;
5487     cm_fid_t    Fid;
5488     afs_uint32  code;
5489     cm_req_t    req;
5490     cm_key_t    key;
5491     DWORD       i;
5492     DWORD       status;
5493
5494     ProcessId.QuadPart = pBRURequestCB->ProcessId;
5495
5496     RDR_InitReq(&req, bWow64);
5497
5498     osi_Log4(afsd_logp, "RDR_ByteRangeUnlock File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
5499               FileId.Cell, FileId.Volume,
5500               FileId.Vnode, FileId.Unique);
5501     osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
5502              ProcessId.HighPart, ProcessId.LowPart);
5503
5504     Length = sizeof( AFSByteRangeUnlockResultCB) + ((pBRURequestCB->Count - 1) * sizeof(AFSByteRangeLockResult));
5505     if (Length > ResultBufferLength) {
5506         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult));
5507         if (!(*ResultCB))
5508             return;
5509         memset( *ResultCB, 0, sizeof(AFSCommResult));
5510         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
5511         return;
5512     }
5513
5514     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
5515     if (!(*ResultCB))
5516         return;
5517     memset( *ResultCB, '\0', Length + sizeof( AFSCommResult) );
5518     (*ResultCB)->ResultBufferLength = Length;
5519
5520     pResultCB = (AFSByteRangeUnlockResultCB *)(*ResultCB)->ResultData;
5521     pResultCB->Count = pBRURequestCB->Count;
5522
5523     /* Allocate the extents from the buffer package */
5524     Fid.cell = FileId.Cell;
5525     Fid.volume = FileId.Volume;
5526     Fid.vnode = FileId.Vnode;
5527     Fid.unique = FileId.Unique;
5528     Fid.hash = FileId.Hash;
5529
5530     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
5531     if (code) {
5532         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5533         (*ResultCB)->ResultStatus = status;
5534         (*ResultCB)->ResultBufferLength = 0;
5535         osi_Log2(afsd_logp, "RDR_ByteRangeUnlock cm_GetSCache FID failure code=0x%x status=0x%x",
5536                   code, status);
5537         return;
5538     }
5539
5540     lock_ObtainWrite(&scp->rw);
5541
5542     /* start by looking up the file's end */
5543     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5544                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5545     if (code) {
5546         lock_ReleaseWrite(&scp->rw);
5547         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5548         (*ResultCB)->ResultStatus = status;
5549         (*ResultCB)->ResultBufferLength = 0;
5550         osi_Log3(afsd_logp, "RDR_ByteRangeUnlock cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
5551                  scp, code, status);
5552         return;
5553     }
5554
5555     /* the scp is now locked and current */
5556     key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
5557
5558     for ( i=0; i<pBRURequestCB->Count; i++ ) {
5559         pResultCB->Result[i].LockType = pBRURequestCB->Request[i].LockType;
5560         pResultCB->Result[i].Offset = pBRURequestCB->Request[i].Offset;
5561         pResultCB->Result[i].Length = pBRURequestCB->Request[i].Length;
5562
5563         code = cm_Unlock(scp,
5564                          pBRURequestCB->Request[i].LockType == AFS_BYTE_RANGE_LOCK_TYPE_SHARED,
5565                          pBRURequestCB->Request[i].Offset,
5566                          pBRURequestCB->Request[i].Length,
5567                          key, CM_UNLOCK_FLAG_MATCH_RANGE, userp, &req);
5568
5569         if (code) {
5570             osi_Log4(afsd_logp, "RDR_ByteRangeUnlock FAILURE code 0x%x type 0x%u offset 0x%x:%x",
5571                      code, pBRURequestCB->Request[i].LockType,
5572                      pBRURequestCB->Request[i].Offset.HighPart,
5573                      pBRURequestCB->Request[i].Offset.LowPart);
5574             osi_Log2(afsd_logp, "... length 0x%x:%x",
5575                      pBRURequestCB->Request[i].Length.HighPart,
5576                      pBRURequestCB->Request[i].Length.LowPart);
5577         }
5578         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5579         pResultCB->Result[i].Status = status;
5580     }
5581
5582     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5583     lock_ReleaseWrite(&scp->rw);
5584     cm_ReleaseSCache(scp);
5585
5586     (*ResultCB)->ResultStatus = 0;
5587     osi_Log0(afsd_logp, "RDR_ByteRangeUnlock SUCCESS");
5588     return;
5589 }
5590
5591 void
5592 RDR_ByteRangeUnlockAll( IN cm_user_t     *userp,
5593                         IN AFSFileID     FileId,
5594                         IN AFSByteRangeUnlockRequestCB *pBRURequestCB,
5595                         IN BOOL bWow64,
5596                         IN DWORD ResultBufferLength,
5597                         IN OUT AFSCommResult **ResultCB)
5598 {
5599     AFSByteRangeUnlockResultCB *pResultCB = NULL;
5600     LARGE_INTEGER ProcessId;
5601     cm_scache_t *scp = NULL;
5602     cm_fid_t    Fid;
5603     afs_uint32  code;
5604     cm_req_t    req;
5605     cm_key_t    key;
5606     DWORD       status;
5607
5608     ProcessId.QuadPart = pBRURequestCB->ProcessId;
5609
5610     RDR_InitReq(&req, bWow64);
5611
5612     osi_Log4(afsd_logp, "RDR_ByteRangeUnlockAll File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
5613               FileId.Cell, FileId.Volume,
5614               FileId.Vnode, FileId.Unique);
5615     osi_Log2(afsd_logp, "... ProcessId 0x%x:%x",
5616              ProcessId.HighPart, ProcessId.LowPart);
5617
5618     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
5619     if (!(*ResultCB))
5620         return;
5621     memset( *ResultCB, '\0', sizeof( AFSCommResult));
5622     (*ResultCB)->ResultBufferLength = 0;
5623
5624     /* Allocate the extents from the buffer package */
5625     Fid.cell = FileId.Cell;
5626     Fid.volume = FileId.Volume;
5627     Fid.vnode = FileId.Vnode;
5628     Fid.unique = FileId.Unique;
5629     Fid.hash = FileId.Hash;
5630
5631     code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
5632     if (code) {
5633         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5634         (*ResultCB)->ResultStatus = status;
5635         (*ResultCB)->ResultBufferLength = 0;
5636         osi_Log2(afsd_logp, "RDR_ByteRangeUnlockAll cm_GetSCache FID failure code=0x%x status=0x%x",
5637                   code, status);
5638         return;
5639     }
5640
5641     lock_ObtainWrite(&scp->rw);
5642
5643     /* start by looking up the file's end */
5644     code = cm_SyncOp(scp, NULL, userp, &req, 0,
5645                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5646     if (code) {
5647         lock_ReleaseWrite(&scp->rw);
5648         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5649         (*ResultCB)->ResultStatus = status;
5650         (*ResultCB)->ResultBufferLength = 0;
5651         osi_Log3(afsd_logp, "RDR_ByteRangeUnlockAll cm_SyncOp failure scp=0x%p code=0x%x status=0x%x",
5652                  scp, code, status);
5653         return;
5654     }
5655
5656     /* the scp is now locked and current */
5657     key = cm_GenerateKey(CM_SESSION_IFS, ProcessId.QuadPart, 0);
5658
5659     code = cm_UnlockByKey(scp, key, 0, userp, &req);
5660
5661     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_LOCK);
5662     lock_ReleaseWrite(&scp->rw);
5663     cm_ReleaseSCache(scp);
5664
5665     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5666     (*ResultCB)->ResultStatus = status;
5667
5668     if (code)
5669         osi_Log1(afsd_logp, "RDR_ByteRangeUnlockAll FAILURE code 0x%x", code);
5670     else
5671         osi_Log0(afsd_logp, "RDR_ByteRangeUnlockAll SUCCESS");
5672     return;
5673
5674 }
5675
5676 void
5677 RDR_GetVolumeInfo( IN cm_user_t     *userp,
5678                    IN AFSFileID     FileId,
5679                    IN BOOL bWow64,
5680                    IN DWORD ResultBufferLength,
5681                    IN OUT AFSCommResult **ResultCB)
5682 {
5683     AFSVolumeInfoCB *pResultCB = NULL;
5684     DWORD       Length;
5685     cm_scache_t *scp = NULL;
5686     cm_volume_t *volp = NULL;
5687     afs_uint32   volType;
5688     cm_fid_t    Fid;
5689     afs_uint32  code;
5690     cm_req_t    req;
5691     DWORD       status;
5692     FILETIME ft = {0x832cf000, 0x01abfcc4}; /* October 1, 1982 00:00:00 +0600 */
5693     afs_uint32  flags;
5694
5695     char volName[32]="(unknown)";
5696     char offLineMsg[256]="server temporarily inaccessible";
5697     char motd[256]="server temporarily inaccessible";
5698     cm_conn_t *connp;
5699     AFSFetchVolumeStatus volStat;
5700     char *Name;
5701     char *OfflineMsg;
5702     char *MOTD;
5703     struct rx_connection * rxconnp;
5704     int sync_done = 0;
5705     int scp_locked = 0;
5706
5707     RDR_InitReq(&req, bWow64);
5708
5709     osi_Log4(afsd_logp, "RDR_GetVolumeInfo File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
5710              FileId.Cell, FileId.Volume,
5711              FileId.Vnode, FileId.Unique);
5712
5713     Length = sizeof( AFSCommResult) + sizeof(AFSVolumeInfoCB);
5714     if (sizeof(AFSVolumeInfoCB) > ResultBufferLength) {
5715         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
5716         if (!(*ResultCB))
5717             return;
5718         memset( *ResultCB, 0, sizeof(AFSCommResult));
5719         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
5720         return;
5721     }
5722
5723     *ResultCB = (AFSCommResult *)malloc( Length );
5724     if (!(*ResultCB))
5725         return;
5726     memset( *ResultCB, '\0', Length );
5727     (*ResultCB)->ResultBufferLength = sizeof(AFSVolumeInfoCB);
5728     pResultCB = (AFSVolumeInfoCB *)(*ResultCB)->ResultData;
5729
5730     if (FileId.Cell != 0) {
5731         cm_SetFid(&Fid, FileId.Cell, FileId.Volume, 1, 1);
5732         code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
5733         if (code) {
5734             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5735             (*ResultCB)->ResultStatus = status;
5736             (*ResultCB)->ResultBufferLength = 0;
5737             osi_Log2(afsd_logp, "RDR_GetVolumeInfo cm_GetSCache FID failure code=0x%x status=0x%x",
5738                       code, status);
5739             return;
5740         }
5741     } else {
5742         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
5743         osi_Log0(afsd_logp, "RDR_GetVolumeInfo Object Name Invalid - Cell = 0");
5744         return;
5745     }
5746     lock_ObtainWrite(&scp->rw);
5747     scp_locked = 1;
5748
5749     pResultCB->SectorsPerAllocationUnit = 1;
5750     pResultCB->BytesPerSector = 1024;
5751
5752     pResultCB->CellID = scp->fid.cell;
5753     pResultCB->VolumeID = scp->fid.volume;
5754     pResultCB->Characteristics = FILE_REMOTE_DEVICE;
5755     pResultCB->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK |
5756         FILE_SUPPORTS_HARD_LINKS | FILE_SUPPORTS_REPARSE_POINTS;
5757
5758     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
5759          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
5760     {
5761         pResultCB->TotalAllocationUnits.QuadPart = 100;
5762         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
5763
5764         pResultCB->AvailableAllocationUnits.QuadPart = 0;
5765         pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
5766
5767         pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( "Freelance.Local.Root", -1, pResultCB->VolumeLabel,
5768                                                        (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
5769         if ( pResultCB->VolumeLabelLength )
5770             pResultCB->VolumeLabelLength--;
5771
5772         pResultCB->CellLength = cm_Utf8ToUtf16( "Freelance.Local", -1, pResultCB->Cell,
5773                                                 (sizeof(pResultCB->Cell) / sizeof(WCHAR)) + 1);
5774         if ( pResultCB->CellLength )
5775             pResultCB->CellLength--;
5776     } else {
5777         volp = cm_GetVolumeByFID(&scp->fid);
5778         if (!volp) {
5779             code = CM_ERROR_NOSUCHVOLUME;
5780             goto _done;
5781         }
5782         volType = cm_VolumeType(volp, scp->fid.volume);
5783
5784         if (volType == ROVOL || volType == BACKVOL)
5785             pResultCB->FileSystemAttributes |= FILE_READ_ONLY_VOLUME;
5786
5787         flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS;
5788         if (scp->volumeCreationDate == 0)
5789             flags |= CM_SCACHESYNC_FORCECB;
5790         code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ, flags);
5791         if (code == 0)
5792         {
5793             sync_done = 1;
5794
5795             Name = volName;
5796             OfflineMsg = offLineMsg;
5797             MOTD = motd;
5798             lock_ReleaseWrite(&scp->rw);
5799             scp_locked = 0;
5800
5801             do {
5802                 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
5803                 if (code) continue;
5804
5805                 rxconnp = cm_GetRxConn(connp);
5806                 code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
5807                                               &volStat, &Name, &OfflineMsg, &MOTD);
5808                 rx_PutConnection(rxconnp);
5809
5810             } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
5811             code = cm_MapRPCError(code, &req);
5812         }
5813
5814         if ( scp->volumeCreationDate )
5815             cm_LargeSearchTimeFromUnixTime(&ft, scp->volumeCreationDate);
5816         memcpy(&pResultCB->VolumeCreationTime, &ft, sizeof(ft));
5817
5818         if (code == 0) {
5819             if (volType == ROVOL || volType == BACKVOL) {
5820                 pResultCB->TotalAllocationUnits.QuadPart = volStat.BlocksInUse;
5821                 pResultCB->AvailableAllocationUnits.QuadPart = 0;
5822             } else {
5823                 if (volStat.MaxQuota)
5824                 {
5825                     pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
5826                     pResultCB->AvailableAllocationUnits.QuadPart =
5827                         min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
5828                 }
5829                 else
5830                 {
5831                     pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
5832                     pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
5833                 }
5834             }
5835         } else {
5836             /*
5837              * Lie about the available space.  Out of quota errors will need
5838              * detected when the file server rejects the store data.
5839              */
5840             pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
5841             pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
5842             code = 0;
5843         }
5844
5845         pResultCB->VolumeLabelLength = cm_Utf8ToUtf16( volp->namep, -1, pResultCB->VolumeLabel,
5846                                                        (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) + 1);
5847
5848         if ( pResultCB->VolumeLabelLength) {
5849
5850             /* add .readonly and .backup if appropriate */
5851             switch ( volType) {
5852             case ROVOL:
5853                 pResultCB->VolumeLabelLength--;
5854                 pResultCB->VolumeLabelLength += cm_Utf8ToUtf16( ".readonly", -1,
5855                                                                 &pResultCB->VolumeLabel[ pResultCB->VolumeLabelLength],
5856                                                                 (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) - pResultCB->VolumeLabelLength + 1);
5857                 break;
5858
5859             case BACKVOL:
5860                 pResultCB->VolumeLabelLength--;
5861                 pResultCB->VolumeLabelLength += cm_Utf8ToUtf16( ".backup", -1,
5862                                                                 &pResultCB->VolumeLabel[ pResultCB->VolumeLabelLength],
5863                                                                 (sizeof(pResultCB->VolumeLabel) / sizeof(WCHAR)) - pResultCB->VolumeLabelLength + 1);
5864                 break;
5865             }
5866         }
5867
5868         /* do not include the trailing nul */
5869         if ( pResultCB->VolumeLabelLength )
5870             pResultCB->VolumeLabelLength--;
5871
5872         pResultCB->CellLength = cm_Utf8ToUtf16( volp->cellp->name, -1, pResultCB->Cell,
5873                                                 (sizeof(pResultCB->Cell) / sizeof(WCHAR)) + 1);
5874
5875         /* do not include the trailing nul */
5876         if ( pResultCB->CellLength )
5877             pResultCB->CellLength--;
5878
5879         if (sync_done) {
5880             if (!scp_locked) {
5881                 lock_ObtainWrite(&scp->rw);
5882                 scp_locked = 1;
5883             }
5884             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5885         }
5886     }
5887     pResultCB->VolumeLabelLength *= sizeof(WCHAR);  /* convert to bytes from chars */
5888     pResultCB->CellLength *= sizeof(WCHAR);         /* convert to bytes from chars */
5889
5890   _done:
5891     if (scp_locked)
5892         lock_ReleaseWrite(&scp->rw);
5893     if (volp)
5894        cm_PutVolume(volp);
5895     cm_ReleaseSCache(scp);
5896
5897     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5898     (*ResultCB)->ResultStatus = status;
5899     osi_Log0(afsd_logp, "RDR_GetVolumeInfo SUCCESS");
5900     return;
5901 }
5902
5903 void
5904 RDR_GetVolumeSizeInfo( IN cm_user_t     *userp,
5905                    IN AFSFileID     FileId,
5906                    IN BOOL bWow64,
5907                    IN DWORD ResultBufferLength,
5908                    IN OUT AFSCommResult **ResultCB)
5909 {
5910     AFSVolumeSizeInfoCB *pResultCB = NULL;
5911     DWORD       Length;
5912     cm_scache_t *scp = NULL;
5913     cm_volume_t *volp = NULL;
5914     afs_uint32   volType;
5915     cm_fid_t    Fid;
5916     afs_uint32  code;
5917     cm_req_t    req;
5918     DWORD       status;
5919
5920     char volName[32]="(unknown)";
5921     char offLineMsg[256]="server temporarily inaccessible";
5922     char motd[256]="server temporarily inaccessible";
5923     cm_conn_t *connp;
5924     AFSFetchVolumeStatus volStat;
5925     char *Name;
5926     char *OfflineMsg;
5927     char *MOTD;
5928     struct rx_connection * rxconnp;
5929     int sync_done = 0;
5930     int scp_locked = 0;
5931
5932     RDR_InitReq(&req, bWow64);
5933
5934     osi_Log4(afsd_logp, "RDR_GetVolumeSizeInfo File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
5935              FileId.Cell, FileId.Volume,
5936              FileId.Vnode, FileId.Unique);
5937
5938     Length = sizeof( AFSCommResult) + sizeof(AFSVolumeSizeInfoCB);
5939     if (sizeof(AFSVolumeSizeInfoCB) > ResultBufferLength) {
5940         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
5941         if (!(*ResultCB))
5942             return;
5943         memset( *ResultCB, 0, sizeof(AFSCommResult));
5944         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
5945         return;
5946     }
5947
5948     *ResultCB = (AFSCommResult *)malloc( Length );
5949     if (!(*ResultCB))
5950         return;
5951     memset( *ResultCB, '\0', Length );
5952     (*ResultCB)->ResultBufferLength = sizeof(AFSVolumeSizeInfoCB);
5953     pResultCB = (AFSVolumeSizeInfoCB *)(*ResultCB)->ResultData;
5954
5955     if (FileId.Cell != 0) {
5956         cm_SetFid(&Fid, FileId.Cell, FileId.Volume, 1, 1);
5957         code = cm_GetSCache(&Fid, NULL, &scp, userp, &req);
5958         if (code) {
5959             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
5960             (*ResultCB)->ResultStatus = status;
5961             (*ResultCB)->ResultBufferLength = 0;
5962             osi_Log2(afsd_logp, "RDR_GetVolumeSizeInfo cm_GetSCache FID failure code=0x%x status=0x%x",
5963                       code, status);
5964             return;
5965         }
5966     } else {
5967         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
5968         osi_Log0(afsd_logp, "RDR_GetVolumeSizeInfo Object Name Invalid - Cell = 0");
5969         return;
5970     }
5971     lock_ObtainWrite(&scp->rw);
5972     scp_locked = 1;
5973
5974     pResultCB->SectorsPerAllocationUnit = 1;
5975     pResultCB->BytesPerSector = 1024;
5976
5977     if (scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
5978         scp->fid.volume==AFS_FAKE_ROOT_VOL_ID)
5979     {
5980         pResultCB->TotalAllocationUnits.QuadPart = 100;
5981         pResultCB->AvailableAllocationUnits.QuadPart = 0;
5982     } else {
5983         volp = cm_GetVolumeByFID(&scp->fid);
5984         if (!volp) {
5985             code = CM_ERROR_NOSUCHVOLUME;
5986             goto _done;
5987         }
5988
5989         volType = cm_VolumeType(volp, scp->fid.volume);
5990
5991         code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
5992                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5993         if (code == 0)
5994         {
5995             sync_done = 1;
5996
5997             Name = volName;
5998             OfflineMsg = offLineMsg;
5999             MOTD = motd;
6000             lock_ReleaseWrite(&scp->rw);
6001             scp_locked = 0;
6002
6003             do {
6004                 code = cm_ConnFromFID(&scp->fid, userp, &req, &connp);
6005                 if (code) continue;
6006
6007                 rxconnp = cm_GetRxConn(connp);
6008                 code = RXAFS_GetVolumeStatus(rxconnp, scp->fid.volume,
6009                                               &volStat, &Name, &OfflineMsg, &MOTD);
6010                 rx_PutConnection(rxconnp);
6011
6012             } while (cm_Analyze(connp, userp, &req, &scp->fid, NULL, 0, NULL, NULL, NULL, NULL, code));
6013             code = cm_MapRPCError(code, &req);
6014         }
6015
6016         if (code == 0) {
6017             if (volType == ROVOL || volType == BACKVOL) {
6018                 pResultCB->TotalAllocationUnits.QuadPart = volStat.BlocksInUse;
6019                 pResultCB->AvailableAllocationUnits.QuadPart = 0;
6020             } else {
6021                 if (volStat.MaxQuota)
6022                 {
6023                     pResultCB->TotalAllocationUnits.QuadPart = volStat.MaxQuota;
6024                     pResultCB->AvailableAllocationUnits.QuadPart =
6025                         min(volStat.MaxQuota - volStat.BlocksInUse, volStat.PartBlocksAvail);
6026                 }
6027                 else
6028                 {
6029                     pResultCB->TotalAllocationUnits.QuadPart = volStat.PartMaxBlocks;
6030                     pResultCB->AvailableAllocationUnits.QuadPart = volStat.PartBlocksAvail;
6031                 }
6032             }
6033         } else {
6034             /*
6035              * Lie about the available space.  Out of quota errors will need
6036              * detected when the file server rejects the store data.
6037              */
6038             pResultCB->TotalAllocationUnits.QuadPart = 0x7FFFFFFF;
6039             pResultCB->AvailableAllocationUnits.QuadPart = (volType == ROVOL || volType == BACKVOL) ? 0 : 0x3F000000;
6040             code = 0;
6041         }
6042
6043         if (sync_done) {
6044             if (!scp_locked) {
6045                 lock_ObtainWrite(&scp->rw);
6046                 scp_locked = 1;
6047             }
6048             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6049         }
6050     }
6051
6052   _done:
6053     if (scp_locked)
6054         lock_ReleaseWrite(&scp->rw);
6055     if (volp)
6056        cm_PutVolume(volp);
6057     cm_ReleaseSCache(scp);
6058
6059     smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6060     (*ResultCB)->ResultStatus = status;
6061     osi_Log0(afsd_logp, "RDR_GetVolumeSizeInfo SUCCESS");
6062     return;
6063 }
6064
6065 void
6066 RDR_HoldFid( IN cm_user_t     *userp,
6067              IN AFSHoldFidRequestCB * pHoldFidCB,
6068              IN BOOL bFast,
6069              IN DWORD ResultBufferLength,
6070              IN OUT AFSCommResult **ResultCB)
6071 {
6072     AFSHoldFidResultCB *pResultCB = NULL;
6073     DWORD       index;
6074     DWORD       Length;
6075     cm_req_t    req;
6076
6077     RDR_InitReq(&req, FALSE);
6078
6079     osi_Log1(afsd_logp, "RDR_HoldFid Count=%u", pHoldFidCB->Count);
6080
6081     Length = sizeof(AFSHoldFidResultCB) + (pHoldFidCB->Count-1) * sizeof(AFSFidResult);
6082     if (Length > ResultBufferLength) {
6083         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
6084         if (!(*ResultCB))
6085             return;
6086         memset( *ResultCB, 0, sizeof(AFSCommResult));
6087         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
6088         return;
6089     }
6090     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
6091     if (!(*ResultCB))
6092         return;
6093     memset( *ResultCB, '\0', Length );
6094     (*ResultCB)->ResultBufferLength = Length;
6095     pResultCB = (AFSHoldFidResultCB *)(*ResultCB)->ResultData;
6096
6097     for ( index = 0; index < pHoldFidCB->Count; index++ )
6098     {
6099         cm_scache_t *scp = NULL;
6100         cm_fid_t    Fid;
6101
6102         Fid.cell   = pResultCB->Result[index].FileID.Cell   = pHoldFidCB->FileID[index].Cell;
6103         Fid.volume = pResultCB->Result[index].FileID.Volume = pHoldFidCB->FileID[index].Volume;
6104         Fid.vnode  = pResultCB->Result[index].FileID.Vnode  = pHoldFidCB->FileID[index].Vnode;
6105         Fid.unique = pResultCB->Result[index].FileID.Unique = pHoldFidCB->FileID[index].Unique;
6106         Fid.hash   = pResultCB->Result[index].FileID.Hash   = pHoldFidCB->FileID[index].Hash;
6107
6108         osi_Log4( afsd_logp,
6109                   "RDR_HoldFid File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
6110                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
6111
6112         scp = cm_FindSCache(&Fid);
6113         if (scp) {
6114             RDR_FlagScpInUse( scp, FALSE );
6115             cm_ReleaseSCache(scp);
6116         }
6117         pResultCB->Result[index].Status = 0;
6118     }
6119
6120     (*ResultCB)->ResultStatus = 0;
6121     osi_Log0(afsd_logp, "RDR_HoldFid SUCCESS");
6122     return;
6123 }
6124
6125 void
6126 RDR_ReleaseFid( IN cm_user_t     *userp,
6127                 IN AFSReleaseFidRequestCB * pReleaseFidCB,
6128                 IN BOOL bFast,
6129                 IN DWORD ResultBufferLength,
6130                 IN OUT AFSCommResult **ResultCB)
6131 {
6132     AFSReleaseFidResultCB *pResultCB = NULL;
6133     DWORD       index;
6134     DWORD       Length;
6135     cm_req_t    req;
6136
6137     RDR_InitReq(&req, FALSE);
6138
6139     osi_Log1(afsd_logp, "RDR_ReleaseFid Count=%u", pReleaseFidCB->Count);
6140
6141     Length = sizeof(AFSReleaseFidResultCB) + (pReleaseFidCB->Count ? pReleaseFidCB->Count-1 : 0) * sizeof(AFSFidResult);
6142     if (Length > ResultBufferLength) {
6143         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
6144         if (!(*ResultCB))
6145             return;
6146         memset( *ResultCB, 0, sizeof(AFSCommResult));
6147         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
6148         return;
6149     }
6150     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
6151     if (!(*ResultCB))
6152         return;
6153     memset( *ResultCB, '\0', Length );
6154     (*ResultCB)->ResultBufferLength = Length;
6155     pResultCB = (AFSReleaseFidResultCB *)(*ResultCB)->ResultData;
6156
6157     for ( index = 0; index < pReleaseFidCB->Count; index++ )
6158     {
6159         cm_scache_t *scp = NULL;
6160         cm_fid_t    Fid;
6161
6162         Fid.cell   = pResultCB->Result[index].FileID.Cell   = pReleaseFidCB->FileID[index].Cell;
6163         Fid.volume = pResultCB->Result[index].FileID.Volume = pReleaseFidCB->FileID[index].Volume;
6164         Fid.vnode  = pResultCB->Result[index].FileID.Vnode  = pReleaseFidCB->FileID[index].Vnode;
6165         Fid.unique = pResultCB->Result[index].FileID.Unique = pReleaseFidCB->FileID[index].Unique;
6166         Fid.hash   = pResultCB->Result[index].FileID.Hash   = pReleaseFidCB->FileID[index].Hash;
6167
6168         osi_Log4( afsd_logp,
6169                   "RDR_ReleaseFid File FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
6170                   Fid.cell, Fid.volume, Fid.vnode, Fid.unique);
6171
6172         scp = cm_FindSCache(&Fid);
6173         if (scp) {
6174             lock_ObtainWrite(&scp->rw);
6175             scp->flags &= ~CM_SCACHEFLAG_RDR_IN_USE;
6176             lock_ReleaseWrite(&scp->rw);
6177
6178             cm_ReleaseSCache(scp);
6179         }
6180         pResultCB->Result[index].Status = 0;
6181     }
6182     pResultCB->Count = pReleaseFidCB->Count;
6183
6184     (*ResultCB)->ResultStatus = 0;
6185     osi_Log0(afsd_logp, "RDR_ReleaseFid SUCCESS");
6186     return;
6187 }
6188
6189 /*
6190  * The redirector makes several assumptions regarding the
6191  * SRVSVC and WKSSVC pipes transactions.  First, the interface
6192  * versions are those indicated below.  Secondly, the encoding
6193  * will be performed using NDR version 2.  These assumptions
6194  * may not hold in the future and end-to-end MSRPC Bind
6195  * negotiations may need to be supported.  Of course, these
6196  * are the only interface versions that are supported by the
6197  * service.
6198  */
6199 #define MSRPC_PIPE_PREFIX L".\\"
6200
6201 static const UUID MSRPC_SRVSVC_UUID = {0x4B324FC8, 0x1670, 0x01D3,
6202                                        {0x12, 0x78, 0x5A, 0x47, 0xBF, 0x6E, 0xE1, 0x88}};
6203 #define MSRPC_SRVSVC_NAME L"PIPE\\SRVSVC"
6204 #define MSRPC_SRVSVC_VERS 3
6205
6206 static const UUID MSRPC_WKSSVC_UUID = {0x6BFFD098, 0xA112, 0x3610,
6207                                        {0x98, 0x33, 0x46, 0xC3, 0xF8, 0x7E, 0x34, 0x5A}};
6208 #define MSRPC_WKSSVC_NAME L"PIPE\\WKSSVC"
6209 #define MSRPC_WKSSVC_VERS 1
6210
6211 static const UUID MSRPC_NDR_UUID = {0x8A885D04, 0x1CEB, 0x11C9,
6212                                     {0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60}};
6213 #define MSRPC_NDR_NAME    L"NDR"
6214 #define MSRPC_NDR_VERS    2
6215
6216 extern RPC_IF_HANDLE srvsvc_v3_0_s_ifspec;
6217 extern RPC_IF_HANDLE wkssvc_v1_0_s_ifspec;
6218
6219 void
6220 RDR_PipeOpen( IN cm_user_t *userp,
6221               IN AFSFileID  ParentId,
6222               IN WCHAR     *Name,
6223               IN DWORD      NameLength,
6224               IN AFSPipeOpenCloseRequestCB *pPipe_CB,
6225               IN BOOL bWow64,
6226               IN DWORD ResultBufferLength,
6227               IN OUT AFSCommResult **ResultCB)
6228 {
6229     cm_fid_t    ParentFid;
6230     cm_fid_t    RootFid;
6231
6232     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
6233     if (!(*ResultCB))
6234         return;
6235
6236     memset( *ResultCB,
6237             '\0',
6238             sizeof( AFSCommResult));
6239
6240     /* Get the active directory */
6241     ParentFid.cell = ParentId.Cell;
6242     ParentFid.volume = ParentId.Volume;
6243     ParentFid.vnode = ParentId.Vnode;
6244     ParentFid.unique = ParentId.Unique;
6245     ParentFid.hash = ParentId.Hash;
6246
6247     /* Get the root directory */
6248     RootFid.cell = pPipe_CB->RootId.Cell;
6249     RootFid.volume = pPipe_CB->RootId.Volume;
6250     RootFid.vnode = pPipe_CB->RootId.Vnode;
6251     RootFid.unique = pPipe_CB->RootId.Unique;
6252     RootFid.hash = pPipe_CB->RootId.Hash;
6253
6254     /* Create the pipe index */
6255     (*ResultCB)->ResultStatus =
6256       RDR_SetupPipe( pPipe_CB->RequestId, &ParentFid, &RootFid,
6257                      Name, NameLength, userp);
6258     return;
6259 }
6260
6261
6262 void
6263 RDR_PipeClose( IN cm_user_t *userp,
6264                IN AFSFileID  ParentId,
6265                IN AFSPipeOpenCloseRequestCB *pPipe_CB,
6266                IN BOOL bWow64,
6267                IN DWORD ResultBufferLength,
6268                IN OUT AFSCommResult **ResultCB)
6269 {
6270     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
6271     if (!(*ResultCB))
6272         return;
6273
6274     memset( *ResultCB,
6275             '\0',
6276             sizeof( AFSCommResult));
6277
6278     /* Cleanup the pipe index */
6279     RDR_CleanupPipe(pPipe_CB->RequestId);
6280
6281     return;
6282 }
6283
6284
6285 void
6286 RDR_PipeWrite( IN cm_user_t *userp,
6287                IN AFSFileID  ParentId,
6288                IN AFSPipeIORequestCB *pPipe_CB,
6289                IN BYTE *pPipe_Data,
6290                IN BOOL bWow64,
6291                IN DWORD ResultBufferLength,
6292                IN OUT AFSCommResult **ResultCB)
6293 {
6294     AFSPipeIOResultCB *pResultCB;
6295     cm_scache_t *dscp = NULL;
6296     afs_uint32  code;
6297     cm_req_t    req;
6298     DWORD       status;
6299
6300     RDR_InitReq(&req, bWow64);
6301
6302     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
6303     if (!(*ResultCB))
6304         return;
6305
6306     memset( *ResultCB,
6307             '\0',
6308             sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
6309
6310     pResultCB = (AFSPipeIOResultCB *)(*ResultCB)->ResultData;
6311
6312     code = RDR_Pipe_Write( pPipe_CB->RequestId, pPipe_CB->BufferLength, pPipe_Data, &req, userp);
6313     if (code) {
6314         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6315         (*ResultCB)->ResultStatus = status;
6316         return;
6317     }
6318
6319     pResultCB->BytesProcessed = pPipe_CB->BufferLength;
6320     (*ResultCB)->ResultBufferLength = sizeof( AFSPipeIOResultCB);
6321 }
6322
6323
6324 void
6325 RDR_PipeRead( IN cm_user_t *userp,
6326               IN AFSFileID  ParentId,
6327               IN AFSPipeIORequestCB *pPipe_CB,
6328               IN BOOL bWow64,
6329               IN DWORD ResultBufferLength,
6330               IN OUT AFSCommResult **ResultCB)
6331 {
6332     BYTE *pPipe_Data;
6333     cm_scache_t *dscp = NULL;
6334     afs_uint32  code;
6335     cm_req_t    req;
6336     DWORD       status;
6337
6338     RDR_InitReq(&req, bWow64);
6339
6340     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
6341     if (!(*ResultCB))
6342         return;
6343
6344     memset( *ResultCB,
6345             '\0',
6346             sizeof( AFSCommResult));
6347
6348     pPipe_Data = (BYTE *)(*ResultCB)->ResultData;
6349
6350     code = RDR_Pipe_Read( pPipe_CB->RequestId, ResultBufferLength, pPipe_Data,
6351                           &(*ResultCB)->ResultBufferLength, &req, userp);
6352     if (code) {
6353         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6354         (*ResultCB)->ResultStatus = status;
6355         return;
6356     }
6357 }
6358
6359
6360 void
6361 RDR_PipeSetInfo( IN cm_user_t *userp,
6362                  IN AFSFileID  ParentId,
6363                  IN AFSPipeInfoRequestCB *pPipeInfo_CB,
6364                  IN BYTE *pPipe_Data,
6365                  IN BOOL bWow64,
6366                  IN DWORD ResultBufferLength,
6367                  IN OUT AFSCommResult **ResultCB)
6368 {
6369     cm_scache_t *dscp = NULL;
6370     cm_req_t    req;
6371     DWORD       status;
6372
6373     RDR_InitReq(&req, bWow64);
6374
6375     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult));
6376     if (!(*ResultCB))
6377         return;
6378
6379     memset( *ResultCB,
6380             '\0',
6381             sizeof( AFSCommResult));
6382
6383     status = RDR_Pipe_SetInfo( pPipeInfo_CB->RequestId, pPipeInfo_CB->InformationClass,
6384                                pPipeInfo_CB->BufferLength, pPipe_Data, &req, userp);
6385
6386     (*ResultCB)->ResultStatus = status;
6387 }
6388
6389
6390 void
6391 RDR_PipeQueryInfo( IN cm_user_t *userp,
6392                    IN AFSFileID  ParentId,
6393                    IN AFSPipeInfoRequestCB *pPipeInfo_CB,
6394                    IN BOOL bWow64,
6395                    IN DWORD ResultBufferLength,
6396                    IN OUT AFSCommResult **ResultCB)
6397 {
6398     BYTE *pPipe_Data;
6399     cm_scache_t *dscp = NULL;
6400     cm_req_t    req;
6401     DWORD       status;
6402
6403     RDR_InitReq(&req, bWow64);
6404
6405     *ResultCB = (AFSCommResult *)malloc( sizeof( AFSCommResult) + ResultBufferLength);
6406     if (!(*ResultCB))
6407         return;
6408
6409     memset( *ResultCB,
6410             '\0',
6411             sizeof( AFSCommResult) + sizeof(AFSPipeIOResultCB));
6412
6413     pPipe_Data = (BYTE *)(*ResultCB)->ResultData;
6414
6415     status = RDR_Pipe_QueryInfo( pPipeInfo_CB->RequestId, pPipeInfo_CB->InformationClass,
6416                                  ResultBufferLength, pPipe_Data,
6417                                  &(*ResultCB)->ResultBufferLength, &req, userp);
6418
6419     (*ResultCB)->ResultStatus = status;
6420 }
6421
6422 void
6423 RDR_PipeTransceive( IN cm_user_t     *userp,
6424                     IN AFSFileID  ParentId,
6425                     IN AFSPipeIORequestCB *pPipe_CB,
6426                     IN BYTE *pPipe_InData,
6427                     IN BOOL bWow64,
6428                     IN DWORD ResultBufferLength,
6429                     IN OUT AFSCommResult **ResultCB)
6430 {
6431     /*
6432      * This function processes a Pipe Service request
6433      * that would normally be sent to a LAN Manager server
6434      * across an authenticated SMB-PIPE/MSRPC/SVC request
6435      * stack.  The request is being sent here because the
6436      * application (e.g., Explorer Shell or Common Control File
6437      * dialog) believes that because the UNC path it is
6438      * processing has specified a server name that is not
6439      * "." and that the Server is remote and that the Share
6440      * list cannot be obtained using the Network Provider
6441      * interface.
6442      *
6443      * The file system driver is faking the Bind-Ack response
6444      * to the MSRPC Bind request but cannot decode the NDR
6445      * encoded Pipe Service requests.  For that we will use
6446      * the service's MSRPC module.  However, unlike the SMB
6447      * server usage we must fake the MSRPC Bind exchange and
6448      * map the PipeName to an interface instead of using the
6449      * GUID specified in the MSRPC Bind request.
6450      *
6451      * None of the requests that are being processed by the
6452      * service require authentication.  As a result the userp
6453      * parameter will be ignored.
6454      *
6455      * Although there are dozens of Pipe Services, the only
6456      * ones that we are implementing are WKSSVC and SRVSVC.
6457      * These support NetShareEnum, NetShareGetInfo,
6458      * NetServerGetInfo, and NetWorkstaGetInfo which are
6459      * commonly queried by NET VIEW, the Explorer Shell,
6460      * and the Common Control File dialog.
6461      */
6462     BYTE *pPipe_OutData;
6463     cm_scache_t *dscp = NULL;
6464     afs_uint32  code;
6465     cm_req_t    req;
6466     DWORD       status;
6467     DWORD Length = ResultBufferLength + sizeof( AFSCommResult);
6468
6469     RDR_InitReq(&req, bWow64);
6470
6471     *ResultCB = (AFSCommResult *)malloc( Length);
6472     if (!(*ResultCB))
6473         return;
6474     memset( *ResultCB, '\0', Length );
6475
6476     code = RDR_Pipe_Write( pPipe_CB->RequestId, pPipe_CB->BufferLength, pPipe_InData, &req, userp);
6477     if (code) {
6478         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6479         osi_Log2( afsd_logp, "RDR_Pipe_Transceive Write FAILURE code=0x%x status=0x%x",
6480                   code, status);
6481         (*ResultCB)->ResultStatus = status;
6482         return;
6483     }
6484
6485     pPipe_OutData = (BYTE *)(*ResultCB)->ResultData;
6486     code = RDR_Pipe_Read( pPipe_CB->RequestId, ResultBufferLength, pPipe_OutData,
6487                           &(*ResultCB)->ResultBufferLength, &req, userp);
6488     if (code) {
6489         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6490         osi_Log2( afsd_logp, "RDR_Pipe_Transceive Read FAILURE code=0x%x status=0x%x",
6491                   code, status);
6492         (*ResultCB)->ResultStatus = status;
6493         return;
6494     }
6495
6496     (*ResultCB)->ResultStatus = 0;
6497     osi_Log0(afsd_logp, "RDR_Pipe_Transceive SUCCESS");
6498 }
6499
6500 void
6501 RDR_ReadFile( IN cm_user_t     *userp,
6502               IN AFSFileID      FileID,
6503               IN LARGE_INTEGER *Offset,
6504               IN ULONG          BytesToRead,
6505               IN PVOID          Buffer,
6506               IN BOOL           bWow64,
6507               IN BOOL           bCacheBypass,
6508               IN DWORD          ResultBufferLength,
6509               IN OUT AFSCommResult **ResultCB)
6510 {
6511     AFSFileIOResultCB * pFileIOResultCB;
6512     DWORD         status;
6513     ULONG         Length;
6514     ULONG         ulBytesRead = 0;
6515     afs_uint32    code = 0;
6516     cm_fid_t      fid;
6517     cm_scache_t * scp = NULL;
6518     cm_req_t      req;
6519
6520     RDR_InitReq(&req, bWow64);
6521
6522     osi_Log4(afsd_logp, "RDR_ReadFile FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
6523              FileID.Cell, FileID.Volume, FileID.Vnode, FileID.Unique);
6524
6525     Length = sizeof(AFSFileIOResultCB);
6526     if (Length > ResultBufferLength) {
6527         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
6528         if (!(*ResultCB))
6529             return;
6530         memset( *ResultCB, 0, sizeof(AFSCommResult));
6531         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
6532         return;
6533     }
6534     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
6535     if (!(*ResultCB))
6536         return;
6537     memset( *ResultCB, '\0', Length );
6538     (*ResultCB)->ResultBufferLength = Length;
6539     pFileIOResultCB = (AFSFileIOResultCB *)(*ResultCB)->ResultData;
6540
6541     if ( Buffer == NULL) {
6542         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
6543         osi_Log0(afsd_logp, "RDR_ReadFile Null IOctl Buffer");
6544         return;
6545     }
6546
6547     if (FileID.Cell != 0) {
6548         fid.cell   = FileID.Cell;
6549         fid.volume = FileID.Volume;
6550         fid.vnode  = FileID.Vnode;
6551         fid.unique = FileID.Unique;
6552         fid.hash   = FileID.Hash;
6553
6554         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
6555         if (code) {
6556             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6557             (*ResultCB)->ResultStatus = status;
6558             osi_Log2(afsd_logp, "RDR_ReadFile cm_GetSCache failure code=0x%x status=0x%x",
6559                       code, status);
6560             return;
6561         }
6562     } else {
6563         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
6564         osi_Log0(afsd_logp, "RDR_ReadFile Object Name Invalid - Cell = 0");
6565         return;
6566     }
6567
6568     /* Ensure that the caller can access this file */
6569     lock_ObtainWrite(&scp->rw);
6570     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_READ,
6571                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6572     if (code) {
6573         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6574         (*ResultCB)->ResultStatus = status;
6575         lock_ReleaseWrite(&scp->rw);
6576         cm_ReleaseSCache(scp);
6577         osi_Log2(afsd_logp, "RDR_ReadFile cm_SyncOp failure code=0x%x status=0x%x",
6578                   code, status);
6579         return;
6580     }
6581
6582     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6583
6584     if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
6585         (*ResultCB)->ResultStatus = STATUS_FILE_IS_A_DIRECTORY;
6586         lock_ReleaseWrite(&scp->rw);
6587         cm_ReleaseSCache(scp);
6588         osi_Log1(afsd_logp, "RDR_ReadFile File is a Directory scp=0x%p",
6589                  scp);
6590         return;
6591     }
6592
6593     if (scp->fileType != CM_SCACHETYPE_FILE) {
6594         (*ResultCB)->ResultStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
6595         lock_ReleaseWrite(&scp->rw);
6596         cm_ReleaseSCache(scp);
6597         osi_Log1(afsd_logp, "RDR_ReadFile File is a MountPoint or Link scp=0x%p",
6598                  scp);
6599         return;
6600     }
6601
6602     if ( bCacheBypass) {
6603         //
6604         // Read the file directly into the buffer bypassing the AFS Cache
6605         //
6606         code = cm_GetData( scp, Offset, Buffer, BytesToRead, &ulBytesRead, userp, &req);
6607     } else {
6608         //
6609         // Read the file via the AFS Cache
6610         //
6611         code = raw_ReadData( scp, Offset, BytesToRead, Buffer, &ulBytesRead, userp, &req);
6612     }
6613
6614     if (code) {
6615         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6616         (*ResultCB)->ResultStatus = status;
6617         osi_Log2(afsd_logp, "RDR_ReadFile failure code=0x%x status=0x%x",
6618                  code, status);
6619     } else {
6620         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
6621         pFileIOResultCB->Length = ulBytesRead;
6622         pFileIOResultCB->DataVersion.QuadPart = scp->dataVersion;
6623         pFileIOResultCB->Expiration.QuadPart = scp->cbExpires;
6624     }
6625
6626     lock_ReleaseWrite(&scp->rw);
6627     cm_ReleaseSCache(scp);
6628     return;
6629 }
6630
6631 void
6632 RDR_WriteFile( IN cm_user_t     *userp,
6633                IN AFSFileID      FileID,
6634                IN AFSFileIOCB   *FileIOCB,
6635                IN LARGE_INTEGER *Offset,
6636                IN ULONG          BytesToWrite,
6637                IN PVOID          Buffer,
6638                IN BOOL           bWow64,
6639                IN BOOL           bCacheBypass,
6640                IN DWORD          ResultBufferLength,
6641                IN OUT AFSCommResult **ResultCB)
6642 {
6643     AFSFileIOResultCB * pFileIOResultCB;
6644     DWORD         status;
6645     ULONG         Length;
6646     ULONG         ulBytesWritten = 0;
6647     afs_uint32    code = 0;
6648     cm_fid_t      fid;
6649     cm_scache_t * scp = NULL;
6650     cm_req_t      req;
6651
6652     RDR_InitReq(&req, bWow64);
6653
6654     osi_Log4(afsd_logp, "RDR_WriteFile FID cell=0x%x vol=0x%x vn=0x%x uniq=0x%x",
6655              FileID.Cell, FileID.Volume, FileID.Vnode, FileID.Unique);
6656
6657     Length = sizeof(AFSFileIOResultCB);
6658     if (Length > ResultBufferLength) {
6659         *ResultCB = (AFSCommResult *)malloc(sizeof(AFSCommResult) );
6660         if (!(*ResultCB))
6661             return;
6662         memset( *ResultCB, 0, sizeof(AFSCommResult));
6663         (*ResultCB)->ResultStatus = STATUS_BUFFER_OVERFLOW;
6664         return;
6665     }
6666     *ResultCB = (AFSCommResult *)malloc( Length + sizeof( AFSCommResult) );
6667     if (!(*ResultCB))
6668         return;
6669     memset( *ResultCB, '\0', Length );
6670     (*ResultCB)->ResultBufferLength = Length;
6671     pFileIOResultCB = (AFSFileIOResultCB *)(*ResultCB)->ResultData;
6672
6673     if ( Buffer == NULL) {
6674         (*ResultCB)->ResultStatus = STATUS_INVALID_PARAMETER;
6675         osi_Log0(afsd_logp, "RDR_WriteFile Null IOctl Buffer");
6676         return;
6677     }
6678
6679     if (FileID.Cell != 0) {
6680         fid.cell   = FileID.Cell;
6681         fid.volume = FileID.Volume;
6682         fid.vnode  = FileID.Vnode;
6683         fid.unique = FileID.Unique;
6684         fid.hash   = FileID.Hash;
6685
6686         code = cm_GetSCache(&fid, NULL, &scp, userp, &req);
6687         if (code) {
6688             smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6689             (*ResultCB)->ResultStatus = status;
6690             osi_Log2(afsd_logp, "RDR_WriteFile cm_GetSCache failure code=0x%x status=0x%x",
6691                       code, status);
6692             return;
6693         }
6694     } else {
6695         (*ResultCB)->ResultStatus = STATUS_OBJECT_NAME_INVALID;
6696         osi_Log0(afsd_logp, "RDR_WriteFile Object Name Invalid - Cell = 0");
6697         return;
6698     }
6699
6700     /* Ensure that the caller can access this file */
6701     lock_ObtainWrite(&scp->rw);
6702     code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_WRITE,
6703                       CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6704     if (code == CM_ERROR_NOACCESS && scp->creator == userp) {
6705         code = cm_SyncOp(scp, NULL, userp, &req, PRSFS_INSERT,
6706                           CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6707     }
6708     if (code) {
6709         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6710         (*ResultCB)->ResultStatus = status;
6711         lock_ReleaseWrite(&scp->rw);
6712         cm_ReleaseSCache(scp);
6713         osi_Log2(afsd_logp, "RDR_WriteFile cm_SyncOp failure code=0x%x status=0x%x",
6714                   code, status);
6715         return;
6716     }
6717
6718     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
6719
6720     if (scp->fileType == CM_SCACHETYPE_DIRECTORY) {
6721         (*ResultCB)->ResultStatus = STATUS_FILE_IS_A_DIRECTORY;
6722         lock_ReleaseWrite(&scp->rw);
6723         cm_ReleaseSCache(scp);
6724         osi_Log1(afsd_logp, "RDR_WriteFile File is a Directory scp=0x%p",
6725                  scp);
6726         return;
6727     }
6728
6729     if (scp->fileType != CM_SCACHETYPE_FILE) {
6730         (*ResultCB)->ResultStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;
6731         lock_ReleaseWrite(&scp->rw);
6732         cm_ReleaseSCache(scp);
6733         osi_Log1(afsd_logp, "RDR_WriteFile File is a MountPoint or Link scp=0x%p",
6734                  scp);
6735         return;
6736     }
6737
6738     if (FileIOCB->EndOfFile.QuadPart != scp->length.QuadPart)
6739     {
6740         cm_attr_t setAttr;
6741
6742         memset(&setAttr, 0, sizeof(cm_attr_t));
6743         if (FileIOCB->EndOfFile.QuadPart != scp->length.QuadPart) {
6744             osi_Log4(afsd_logp, "RDR_WriteFile new length fid vol 0x%x vno 0x%x length 0x%x:%x",
6745                      scp->fid.volume, scp->fid.vnode,
6746                      FileIOCB->EndOfFile.HighPart,
6747                      FileIOCB->EndOfFile.LowPart);
6748
6749             setAttr.mask |= CM_ATTRMASK_LENGTH;
6750             setAttr.length.LowPart = FileIOCB->EndOfFile.LowPart;
6751             setAttr.length.HighPart = FileIOCB->EndOfFile.HighPart;
6752             lock_ReleaseWrite(&scp->rw);
6753             code = cm_SetAttr(scp, &setAttr, userp, &req);
6754             osi_Log2(afsd_logp, "RDR_WriteFile cm_SetAttr failure scp=0x%p code 0x%x",
6755                      scp, code);
6756             code = 0;       /* ignore failure */
6757             lock_ObtainWrite(&scp->rw);
6758         }
6759     }
6760
6761     /*
6762      * The input buffer may contain data beyond the end of the file.
6763      * Such data must be discarded.
6764      */
6765     if ( Offset->QuadPart + BytesToWrite > scp->length.QuadPart)
6766     {
6767         if ( Offset->QuadPart > scp->length.QuadPart) {
6768             (*ResultCB)->ResultStatus = STATUS_SUCCESS;
6769             lock_ReleaseWrite(&scp->rw);
6770             cm_ReleaseSCache(scp);
6771             osi_Log1(afsd_logp, "RDR_WriteFile Nothing to do scp=0x%p",
6772                      scp);
6773             return;
6774         }
6775
6776         BytesToWrite -= (afs_uint32)(Offset->QuadPart + BytesToWrite - scp->length.QuadPart);
6777     }
6778
6779     if (bCacheBypass) {
6780         code = cm_DirectWrite( scp, Offset, BytesToWrite,
6781                                CM_DIRECT_SCP_LOCKED,
6782                                userp, &req, Buffer, &ulBytesWritten);
6783     } else {
6784         code = raw_WriteData( scp, Offset, BytesToWrite, Buffer, userp, &req, &ulBytesWritten);
6785     }
6786
6787     if (code) {
6788         smb_MapNTError(cm_MapRPCError(code, &req), &status, TRUE);
6789         (*ResultCB)->ResultStatus = status;
6790         osi_Log2(afsd_logp, "RDR_WriteFile failure code=0x%x status=0x%x",
6791                  code, status);
6792     } else {
6793         (*ResultCB)->ResultStatus = STATUS_SUCCESS;
6794         pFileIOResultCB->Length = ulBytesWritten;
6795         pFileIOResultCB->DataVersion.QuadPart = scp->dataVersion;
6796         pFileIOResultCB->Expiration.QuadPart = scp->cbExpires;
6797     }
6798
6799     lock_ReleaseWrite(&scp->rw);
6800     cm_ReleaseSCache(scp);
6801     return;
6802 }