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