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