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