62495352d38afdef30f988d8dd1901ba6dff49ba
[openafs.git] / src / WINNT / afsd / smb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afs/param.h>
11 #include <afs/stds.h>
12
13 #include <windows.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <malloc.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <time.h>
20
21 #include <osi.h>
22
23 #include "afsd.h"
24
25 #include "smb.h"
26
27 /* These characters are illegal in Windows filenames */
28 static char *illegalChars = "\\/:*?\"<>|";
29 BOOL isWindows2000 = FALSE;
30
31 smb_vc_t *dead_vcp = NULL;
32 smb_vc_t *active_vcp = NULL;
33
34 char *loggedOutName = NULL;
35 smb_user_t *loggedOutUserp = NULL;
36 unsigned long loggedOutTime;
37 int loggedOut = 0;
38
39 int smb_LogoffTokenTransfer;
40 unsigned long smb_LogoffTransferTimeout;
41
42 DWORD last_msg_time = 0;
43
44 long ongoingOps = 0;
45
46 unsigned int sessionGen = 0;
47
48 void afsi_log();
49
50 osi_hyper_t hzero = {0, 0};
51 osi_hyper_t hones = {0xFFFFFFFF, -1};
52
53 osi_log_t *smb_logp;
54 osi_rwlock_t smb_globalLock;
55 osi_rwlock_t smb_rctLock;
56
57 unsigned char smb_LANadapter;
58
59 /* for debugging */
60 long smb_maxObsConcurrentCalls=0;
61 long smb_concurrentCalls=0;
62
63 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
64
65 smb_packet_t *smb_packetFreeListp;
66 smb_ncb_t *smb_ncbFreeListp;
67
68 int smb_NumServerThreads;
69
70 int numNCBs, numSessions;
71
72 #define NCBmax 100
73 HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
74 HANDLE **NCBreturns;
75 DWORD NCBsessions[NCBmax];
76 NCB *NCBs[NCBmax];
77 struct smb_packet *bufs[NCBmax];
78
79 #define Sessionmax 100
80 HANDLE SessionEvents[Sessionmax];
81 unsigned short LSNs[Sessionmax];
82 BOOL dead_sessions[Sessionmax];
83
84 /* for raw I/O */
85 osi_mutex_t smb_RawBufLock;
86 char *smb_RawBufs;
87
88 #define RAWTIMEOUT INFINITE
89
90 /* for raw write */
91 typedef struct raw_write_cont {
92         long code;
93         osi_hyper_t offset;
94         long count;
95         char *buf;
96         int writeMode;
97         long alreadyWritten;
98 } raw_write_cont_t;
99
100 /* dir search stuff */
101 long smb_dirSearchCounter = 1;
102 smb_dirSearch_t *smb_firstDirSearchp;
103 smb_dirSearch_t *smb_lastDirSearchp;
104
105 /* global state about V3 protocols */
106 int smb_useV3;          /* try to negotiate V3 */
107
108 /* MessageBox or something like it */
109 int (WINAPI *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
110
111 /* GMT time info:
112  * Time in Unix format of midnight, 1/1/1970 local time.
113  * When added to dosUTime, gives Unix (AFS) time.
114  */
115 long smb_localZero;
116
117 /* Time difference for converting to kludge-GMT */
118 int smb_NowTZ;
119
120 char *smb_localNamep;
121
122 smb_vc_t *smb_allVCsp;
123
124 smb_waitingLock_t *smb_allWaitingLocks;
125
126 /* forward decl */
127 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
128         NCB *ncbp, raw_write_cont_t *rwcp);
129
130 /*
131  * Demo expiration
132  *
133  * To build an expiring version, comment out the definition of NOEXPIRE,
134  * and set the definition of EXPIREDATE to the desired value.
135  */
136 #define NOEXPIRE 1
137 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
138
139
140
141
142 /* scache must be locked */
143 unsigned int smb_Attributes(cm_scache_t *scp)
144 {
145         unsigned int attrs;
146
147         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
148                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
149                         attrs = 0x10;
150         else
151                 attrs = 0;
152
153         /*
154          * We used to mark a file RO if it was in an RO volume, but that
155          * turns out to be impolitic in NT.  See defect 10007.
156          */
157 #ifdef notdef
158         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
159 #endif
160         if ((scp->unixModeBits & 0222) == 0)
161                 attrs |= 1;     /* turn on read-only flag */
162
163         return attrs;
164 }
165
166 static int ExtractBits(WORD bits, short start, short len)
167 {
168         int end;
169         WORD num;
170
171         end = start + len;
172         
173         num = bits << (16 - end);
174         num = num >> ((16 - end) + start);
175         
176         return (int)num;
177 }
178
179 void ShowUnixTime(char *FuncName, long unixTime)
180 {
181         FILETIME ft;
182         WORD wDate, wTime;
183
184         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
185                 
186         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
187                 osi_Log1(afsd_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
188         else {
189                 int day, month, year, sec, min, hour;
190                 char msg[256];
191                 
192                 day = ExtractBits(wDate, 0, 5);
193                 month = ExtractBits(wDate, 5, 4);
194                 year = ExtractBits(wDate, 9, 7) + 1980;
195                 
196                 sec = ExtractBits(wTime, 0, 5);
197                 min = ExtractBits(wTime, 5, 6);
198                 hour = ExtractBits(wTime, 11, 5);
199                 
200                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
201                 osi_Log1(afsd_logp, "%s", osi_LogSaveString(afsd_logp, msg));
202         }
203 }
204
205 /* Determine if we are observing daylight savings time */
206 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
207 {
208         TIME_ZONE_INFORMATION timeZoneInformation;
209         SYSTEMTIME utc, local, localDST;
210
211         /* Get the time zone info. NT uses this to calc if we are in DST. */
212         GetTimeZoneInformation(&timeZoneInformation);
213  
214         /* Return the daylight bias */
215         *pDstBias = timeZoneInformation.DaylightBias;
216
217         /* Return the bias */
218         *pBias = timeZoneInformation.Bias;
219
220         /* Now determine if DST is being observed */
221
222         /* Get the UTC (GMT) time */
223         GetSystemTime(&utc);
224
225         /* Convert UTC time to local time using the time zone info.  If we are
226            observing DST, the calculated local time will include this. 
227         */
228         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
229
230         /* Set the daylight bias to 0.  The daylight bias is the amount of change
231            in time that we use for daylight savings time.  By setting this to 0
232            we cause there to be no change in time during daylight savings time. 
233         */
234         timeZoneInformation.DaylightBias = 0;
235
236         /* Convert the utc time to local time again, but this time without any
237            adjustment for daylight savings time. 
238         */
239         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
240
241         /* If the two times are different, then it means that the localDST that
242            we calculated includes the daylight bias, and therefore we are
243            observing daylight savings time.
244         */
245         *pDST = localDST.wHour != local.wHour;
246 }
247
248 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
249 {
250         BOOL dst;       /* Will be TRUE if observing DST */
251         LONG dstBias;   /* Offset from local time if observing DST */
252         LONG bias;      /* Offset from GMT for local time */
253         
254         /*
255          * This function will adjust the last write time to compensate
256          * for two bugs in the smb client:
257          *
258          *    1) During Daylight Savings Time, the LastWriteTime is ahead
259          *       in time by the DaylightBias (ignoring the sign - the
260          *       DaylightBias is always stored as a negative number).  If
261          *       the DaylightBias is -60, then the LastWriteTime will be
262          *       ahead by 60 minutes.
263          *
264          *    2) If the local time zone is a positive offset from GMT, then
265          *       the LastWriteTime will be the correct local time plus the
266          *       Bias (ignoring the sign - a positive offset from GMT is
267          *       always stored as a negative Bias).  If the Bias is -120,
268          *       then the LastWriteTime will be ahead by 120 minutes.
269          *
270          *    These bugs can occur at the same time.
271          */
272
273         GetTimeZoneInfo(&dst, &dstBias, &bias);
274          
275          /* First adjust for DST */
276         if (dst)
277                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
278                 
279         /* Now adjust for a positive offset from GMT (a negative bias). */
280         if (bias < 0)
281                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
282 }
283
284 /*
285  * Calculate the difference (in seconds) between local time and GMT.
286  * This enables us to convert file times to kludge-GMT.
287  */
288 static void
289 smb_CalculateNowTZ()
290 {
291         time_t t;
292         struct tm gmt_tm, local_tm;
293         int days, hours, minutes, seconds;
294
295         t = time(NULL);
296         gmt_tm = *(gmtime(&t));
297         local_tm = *(localtime(&t));
298
299         days = local_tm.tm_yday - gmt_tm.tm_yday;
300         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
301         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
302         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
303
304         smb_NowTZ = seconds;
305 }
306 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
307 {
308         struct tm *ltp;
309         SYSTEMTIME stm;
310         struct tm localJunk;
311         long ersatz_unixTime;
312
313         /*
314          * Must use kludge-GMT instead of real GMT.
315          * kludge-GMT is computed by adding time zone difference to localtime.
316          *
317          * real GMT would be:
318          * ltp = gmtime(&unixTime);
319          */
320         ersatz_unixTime = unixTime - smb_NowTZ;
321         ltp = localtime(&ersatz_unixTime);
322
323         /* if we fail, make up something */
324         if (!ltp) {
325                 ltp = &localJunk;
326                 localJunk.tm_year = 89 - 20;
327                 localJunk.tm_mon = 4;
328                 localJunk.tm_mday = 12;
329                 localJunk.tm_hour = 0;
330                 localJunk.tm_min = 0;
331                 localJunk.tm_sec = 0;
332         }
333
334         stm.wYear = ltp->tm_year + 1900;
335         stm.wMonth = ltp->tm_mon + 1;
336         stm.wDayOfWeek = ltp->tm_wday;
337         stm.wDay = ltp->tm_mday;
338         stm.wHour = ltp->tm_hour;
339         stm.wMinute = ltp->tm_min;
340         stm.wSecond = ltp->tm_sec;
341         stm.wMilliseconds = 0;
342
343         SystemTimeToFileTime(&stm, largeTimep);
344 }
345
346 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
347 {
348         SYSTEMTIME stm;
349         struct tm lt;
350         long save_timezone;
351
352         FileTimeToSystemTime(largeTimep, &stm);
353
354         lt.tm_year = stm.wYear - 1900;
355         lt.tm_mon = stm.wMonth - 1;
356         lt.tm_wday = stm.wDayOfWeek;
357         lt.tm_mday = stm.wDay;
358         lt.tm_hour = stm.wHour;
359         lt.tm_min = stm.wMinute;
360         lt.tm_sec = stm.wSecond;
361         lt.tm_isdst = -1;
362
363         save_timezone = _timezone;
364         _timezone += smb_NowTZ;
365         *unixTimep = mktime(&lt);
366         _timezone = save_timezone;
367 }
368
369 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
370 {
371         struct tm *ltp;
372         int dosDate;
373         int dosTime;
374         struct tm localJunk;
375
376         ltp = localtime(&unixTime);
377
378         /* if we fail, make up something */
379         if (!ltp) {
380                 ltp = &localJunk;
381                 localJunk.tm_year = 89 - 20;
382                 localJunk.tm_mon = 4;
383                 localJunk.tm_mday = 12;
384                 localJunk.tm_hour = 0;
385                 localJunk.tm_min = 0;
386                 localJunk.tm_sec = 0;
387         }
388
389         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
390         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
391         *dosTimep = (dosDate<<16) | dosTime;
392 }
393
394 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
395 {
396         unsigned short dosDate;
397         unsigned short dosTime;
398         struct tm localTm;
399         
400         dosDate = searchTime & 0xffff;
401         dosTime = (searchTime >> 16) & 0xffff;
402         
403         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
404         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
405         localTm.tm_mday = (dosDate) & 0x1f;
406         localTm.tm_hour = (dosTime>>11) & 0x1f;
407         localTm.tm_min = (dosTime >> 5) & 0x3f;
408         localTm.tm_sec = (dosTime & 0x1f) * 2;
409         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
410         
411         *unixTimep = mktime(&localTm);
412 }
413
414 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
415 {
416         *dosUTimep = unixTime - smb_localZero;
417 }
418
419 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
420 {
421         *unixTimep = dosTime + smb_localZero;
422 }
423
424 smb_vc_t *smb_FindVC(unsigned short lsn, int flags)
425 {
426         smb_vc_t *vcp;
427
428         lock_ObtainWrite(&smb_rctLock);
429         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
430                 if (lsn == vcp->lsn) {
431                         vcp->refCount++;
432                         break;
433                 }
434         }
435         if (!vcp && (flags & SMB_FLAG_CREATE)) {
436                 vcp = malloc(sizeof(*vcp));
437                 memset(vcp, 0, sizeof(*vcp));
438                 vcp->refCount = 1;
439                 vcp->tidCounter = 1;
440                 vcp->fidCounter = 1;
441                 vcp->nextp = smb_allVCsp;
442                 smb_allVCsp = vcp;
443                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
444                 vcp->lsn = lsn;
445         }
446         lock_ReleaseWrite(&smb_rctLock);
447         return vcp;
448 }
449
450 int smb_IsStarMask(char *maskp)
451 {
452         int i;
453         char tc;
454         
455         for(i=0; i<11; i++) {
456                 tc = *maskp++;
457                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
458         }
459         return 0;
460 }
461
462 void smb_ReleaseVC(smb_vc_t *vcp)
463 {
464         lock_ObtainWrite(&smb_rctLock);
465         osi_assert(vcp->refCount-- > 0);
466         lock_ReleaseWrite(&smb_rctLock);
467 }
468
469 void smb_HoldVC(smb_vc_t *vcp)
470 {
471         lock_ObtainWrite(&smb_rctLock);
472         vcp->refCount++;
473         lock_ReleaseWrite(&smb_rctLock);
474 }
475
476 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
477 {
478         smb_tid_t *tidp;
479
480         lock_ObtainWrite(&smb_rctLock);
481         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
482                 if (tid == tidp->tid) {
483                         tidp->refCount++;
484                         break;
485                 }
486         }
487         if (!tidp && (flags & SMB_FLAG_CREATE)) {
488                 tidp = malloc(sizeof(*tidp));
489                 memset(tidp, 0, sizeof(*tidp));
490                 tidp->nextp = vcp->tidsp;
491                 tidp->refCount = 1;
492                 tidp->vcp = vcp;
493                 vcp->tidsp = tidp;
494                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
495                 tidp->tid = tid;
496         }
497         lock_ReleaseWrite(&smb_rctLock);
498         return tidp;
499 }
500
501 void smb_ReleaseTID(smb_tid_t *tidp)
502 {
503         smb_tid_t *tp;
504         smb_tid_t **ltpp;
505         cm_user_t *userp;
506
507         userp = NULL;
508         lock_ObtainWrite(&smb_rctLock);
509         osi_assert(tidp->refCount-- > 0);
510         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
511                 ltpp = &tidp->vcp->tidsp;
512                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
513                         if (tp == tidp) break;
514                 }
515                 osi_assert(tp != NULL);
516                 *ltpp = tp->nextp;
517                 lock_FinalizeMutex(&tidp->mx);
518                 userp = tidp->userp;    /* remember to drop ref later */
519         }
520         lock_ReleaseWrite(&smb_rctLock);
521         if (userp) {
522                 cm_ReleaseUser(userp);
523         }
524 }
525
526 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
527 {
528         smb_user_t *uidp;
529
530         lock_ObtainWrite(&smb_rctLock);
531         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
532                 if (uid == uidp->userID) {
533                         uidp->refCount++;
534                         break;
535                 }
536         }
537         if (!uidp && (flags & SMB_FLAG_CREATE)) {
538                 uidp = malloc(sizeof(*uidp));
539                 memset(uidp, 0, sizeof(*uidp));
540                 uidp->nextp = vcp->usersp;
541                 uidp->refCount = 1;
542                 uidp->vcp = vcp;
543                 vcp->usersp = uidp;
544                 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
545                 uidp->userID = uid;
546         }
547         lock_ReleaseWrite(&smb_rctLock);
548         return uidp;
549 }
550
551 void smb_ReleaseUID(smb_user_t *uidp)
552 {
553         smb_user_t *up;
554         smb_user_t **lupp;
555         cm_user_t *userp;
556
557         userp = NULL;
558         lock_ObtainWrite(&smb_rctLock);
559         osi_assert(uidp->refCount-- > 0);
560         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
561                 lupp = &uidp->vcp->usersp;
562                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
563                         if (up == uidp) break;
564                 }
565                 osi_assert(up != NULL);
566                 *lupp = up->nextp;
567                 lock_FinalizeMutex(&uidp->mx);
568                 userp = uidp->userp;    /* remember to drop ref later */
569         }
570         lock_ReleaseWrite(&smb_rctLock);
571         if (userp) {
572                 cm_ReleaseUserVCRef(userp);
573                 cm_ReleaseUser(userp);
574         }
575 }
576
577 /* retrieve a held reference to a user structure corresponding to an incoming
578  * request.
579  * corresponding release function is cm_ReleaseUser.
580  */
581 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
582 {
583         smb_user_t *uidp;
584         cm_user_t *up;
585         smb_t *smbp;
586         
587         smbp = (smb_t *) inp;
588         uidp = smb_FindUID(vcp, smbp->uid, 0);
589         if (!uidp) return NULL;
590         
591         lock_ObtainMutex(&uidp->mx);
592         up = uidp->userp;
593         cm_HoldUser(up);
594         lock_ReleaseMutex(&uidp->mx);
595
596         smb_ReleaseUID(uidp);
597         
598         return up;
599 }
600
601 /*
602  * Return a pointer to a pathname extracted from a TID structure.  The
603  * TID structure is not held; assume it won't go away.
604  */
605 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
606 {
607         smb_tid_t *tidp;
608         char *tpath;
609
610         tidp = smb_FindTID(vcp, tid, 0);
611         tpath = tidp->pathname;
612         smb_ReleaseTID(tidp);
613         return tpath;
614 }
615
616 /* check to see if we have a chained fid, that is, a fid that comes from an
617  * OpenAndX message that ran earlier in this packet.  In this case, the fid
618  * field in a read, for example, request, isn't set, since the value is
619  * supposed to be inherited from the openAndX call.
620  */
621 int smb_ChainFID(int fid, smb_packet_t *inp)
622 {
623         if (inp->fid == 0 || inp->inCount == 0) return fid;
624         else return inp->fid;
625 }
626
627 /* are we a priv'd user?  What does this mean on NT? */
628 int smb_SUser(cm_user_t *userp)
629 {
630         return 1;
631 }
632
633 /* find a file ID.  If pass in 0, we'll allocate on on a create operation. */
634 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
635 {
636         smb_fid_t *fidp;
637         int newFid;
638         
639         /* figure out if we need to allocate a new file ID */
640         if (fid == 0) {
641                 newFid = 1;
642                 fid = vcp->fidCounter;
643         }
644         else newFid = 0;
645
646         lock_ObtainWrite(&smb_rctLock);
647 retry:
648         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
649                 if (fid == fidp->fid) {
650                         if (newFid) {
651                                 fid++;
652                                 if (fid == 0) fid = 1;
653                                 goto retry;
654                         }
655                         fidp->refCount++;
656                         break;
657                 }
658         }
659         if (!fidp && (flags & SMB_FLAG_CREATE)) {
660                 fidp = malloc(sizeof(*fidp));
661                 memset(fidp, 0, sizeof(*fidp));
662                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
663                 fidp->refCount = 1;
664                 fidp->vcp = vcp;
665                 lock_InitializeMutex(&fidp->mx, "fid_t mutex");
666                 fidp->fid = fid;
667                 fidp->curr_chunk = fidp->prev_chunk = -2;
668                 fidp->raw_write_event = CreateEvent(NULL, FALSE, TRUE, NULL);
669                 if (newFid) {
670                         vcp->fidCounter = fid+1;
671                         if (vcp->fidCounter == 0) vcp->fidCounter = 1;
672                 }
673         }
674         lock_ReleaseWrite(&smb_rctLock);
675         return fidp;
676 }
677
678 void smb_ReleaseFID(smb_fid_t *fidp)
679 {
680         cm_scache_t *scp;
681         smb_vc_t *vcp;
682         smb_ioctl_t *ioctlp;
683
684         scp = NULL;
685         lock_ObtainWrite(&smb_rctLock);
686         osi_assert(fidp->refCount-- > 0);
687         if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
688                 vcp = fidp->vcp;
689                 if (!(fidp->flags & SMB_FID_IOCTL))
690                         scp = fidp->scp;
691                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
692                 CloseHandle(fidp->raw_write_event);
693
694                 /* and see if there is ioctl stuff to free */
695                 ioctlp = fidp->ioctlp;
696                 if (ioctlp) {
697                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
698                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
699                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
700                         free(ioctlp);
701                 }
702
703                 free(fidp);
704         }
705         lock_ReleaseWrite(&smb_rctLock);
706
707         /* now release the scache structure */
708         if (scp) cm_ReleaseSCache(scp);
709 }
710
711 /*
712  * Case-insensitive search for one string in another;
713  * used to find variable names in submount pathnames.
714  */
715 static char *smb_stristr(char *str1, char *str2)
716 {
717         char *cursor;
718
719         for (cursor = str1; *cursor; cursor++)
720                 if (stricmp(cursor, str2) == 0)
721                         return cursor;
722
723         return NULL;
724 }
725
726 /*
727  * Substitute a variable value for its name in a submount pathname.  Variable
728  * name has been identified by smb_stristr() and is in substr.  Variable name
729  * length (plus one) is in substr_size.  Variable value is in newstr.
730  */
731 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
732         char *newstr)
733 {
734         char temp[1024];
735
736         strcpy(temp, substr + substr_size - 1);
737         strcpy(substr, newstr);
738         strcat(str1, temp);
739 }
740
741 char VNUserName[] = "%USERNAME%";
742 char VNLCUserName[] = "%LCUSERNAME%";
743 char VNComputerName[] = "%COMPUTERNAME%";
744 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
745
746 /* find a shareName in the table of submounts */
747 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
748         char **pathNamep)
749 {
750         DWORD len;
751         char pathName[1024];
752         char *var;
753         smb_user_t *uidp;
754         char temp[1024];
755         DWORD sizeTemp;
756
757         if (strcmp(shareName, "IPC$") == 0) {
758                 *pathNamep = NULL;
759                 return 0;
760         }
761
762         if (_stricmp(shareName, "all") == 0) {
763                 *pathNamep = NULL;
764                 return 1;
765         }
766
767         len = GetPrivateProfileString("AFS Submounts", shareName, "",
768                                       pathName, sizeof(pathName), "afsdsbmt.ini");
769         if (len == 0 || len == sizeof(pathName) - 1) {
770                 *pathNamep = NULL;
771                 return 0;
772         }
773
774         while (1)
775         {
776                 if (var = smb_stristr(pathName, VNUserName)) {
777                         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
778                         smb_subst(pathName, var, sizeof(VNUserName),
779                                   uidp->name);
780                         smb_ReleaseUID(uidp);
781                 }
782                 else if (var = smb_stristr(pathName, VNLCUserName)) {
783                         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
784                         strcpy(temp, uidp->name);
785                         _strlwr(temp);
786                         smb_subst(pathName, var, sizeof(VNLCUserName), temp);
787                         smb_ReleaseUID(uidp);
788                 }
789                 else if (var = smb_stristr(pathName, VNComputerName)) {
790                         sizeTemp = sizeof(temp);
791                         GetComputerName((LPTSTR)temp, &sizeTemp);
792                         smb_subst(pathName, var, sizeof(VNComputerName),
793                                   temp);
794                 }
795                 else if (var = smb_stristr(pathName, VNLCComputerName)) {
796                         sizeTemp = sizeof(temp);
797                         GetComputerName((LPTSTR)temp, &sizeTemp);
798                         _strlwr(temp);
799                         smb_subst(pathName, var, sizeof(VNLCComputerName),
800                                   temp);
801                 }
802                 else break;
803         }
804
805         *pathNamep = strdup(pathName);
806         return 1;
807 }
808
809 /* find a dir search structure by cookie value, and return it held.
810  * Must be called with smb_globalLock held.
811  */
812 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
813 {
814         smb_dirSearch_t *dsp;
815         
816         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
817                 if (dsp->cookie == cookie) {
818                         if (dsp != smb_firstDirSearchp) {
819                                 /* move to head of LRU queue, too, if we're not already there */
820                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
821                                         smb_lastDirSearchp = (smb_dirSearch_t *)
822                                                 osi_QPrev(&dsp->q);
823                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
824                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
825                                 if (!smb_lastDirSearchp)
826                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
827                         }
828                         dsp->refCount++;
829                         break;
830                 }
831         }
832         return dsp;
833 }
834
835 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
836 {
837         lock_ObtainWrite(&smb_globalLock);
838         dsp->flags |= SMB_DIRSEARCH_DELETE;
839         lock_ReleaseWrite(&smb_globalLock);
840         lock_ObtainMutex(&dsp->mx);
841         if(dsp->scp != NULL) {
842               lock_ObtainMutex(&dsp->scp->mx);
843               if (dsp->flags & SMB_DIRSEARCH_BULKST) {
844                     dsp->flags &= ~SMB_DIRSEARCH_BULKST;
845                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
846                     dsp->scp->bulkStatProgress = hones;
847               }
848               lock_ReleaseMutex(&dsp->scp->mx);
849         }
850         lock_ReleaseMutex(&dsp->mx);
851 }
852
853 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
854 {
855         cm_scache_t *scp;
856         
857         scp = NULL;
858
859         lock_ObtainWrite(&smb_globalLock);
860         osi_assert(dsp->refCount-- > 0);
861         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
862                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
863                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
864                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
865                 lock_FinalizeMutex(&dsp->mx);
866                 scp = dsp->scp;
867                 free(dsp);
868         }
869         lock_ReleaseWrite(&smb_globalLock);
870         
871         /* do this now to avoid spurious locking hierarchy creation */
872         if (scp) cm_ReleaseSCache(scp);
873 }
874
875 /* find a dir search structure by cookie value, and return it held */
876 smb_dirSearch_t *smb_FindDirSearch(long cookie)
877 {
878         smb_dirSearch_t *dsp;
879
880         lock_ObtainWrite(&smb_globalLock);
881         dsp = smb_FindDirSearchNL(cookie);
882         lock_ReleaseWrite(&smb_globalLock);
883         return dsp;
884 }
885
886 /* GC some dir search entries, in the address space expected by the specific protocol.
887  * Must be called with smb_globalLock held; release the lock temporarily.
888  */
889 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
890 void smb_GCDirSearches(int isV3)
891 {
892         smb_dirSearch_t *prevp;
893         smb_dirSearch_t *tp;
894         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
895         int victimCount;
896         int i;
897         
898         victimCount = 0;        /* how many have we got so far */
899         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
900                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  /* we'll move tp from queue, so
901                                                                  * do this early.
902                                                                  */
903                 /* if no one is using this guy, and we're either in the new protocol,
904                  * or we're in the old one and this is a small enough ID to be useful
905                  * to the old protocol, GC this guy.
906                  */
907                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
908                         /* hold and delete */
909                         tp->flags |= SMB_DIRSEARCH_DELETE;
910                         victimsp[victimCount++] = tp;
911                         tp->refCount++;
912                 }
913
914                 /* don't do more than this */
915                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
916         }
917         
918         /* now release them */
919         lock_ReleaseWrite(&smb_globalLock);
920         for(i = 0; i < victimCount; i++) {
921                 smb_ReleaseDirSearch(victimsp[i]);
922         }
923         lock_ObtainWrite(&smb_globalLock);
924 }
925
926 /* function for allocating a dir search entry.  We need these to remember enough context
927  * since we don't get passed the path from call to call during a directory search.
928  *
929  * Returns a held dir search structure, and bumps the reference count on the vnode,
930  * since it saves a pointer to the vnode.
931  */
932 smb_dirSearch_t *smb_NewDirSearch(int isV3)
933 {
934         smb_dirSearch_t *dsp;
935         int counter;
936         int maxAllowed;
937
938         lock_ObtainWrite(&smb_globalLock);
939         counter = 0;
940
941         /* what's the biggest ID allowed in this version of the protocol */
942         if (isV3) maxAllowed = 65535;
943         else maxAllowed = 255;
944
945         while(1) {
946                 /* twice so we have enough tries to find guys we GC after one pass;
947                  * 10 extra is just in case I mis-counted.
948                  */
949                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
950                         __FILE__, __LINE__);
951                 if (smb_dirSearchCounter > maxAllowed) {
952                         smb_dirSearchCounter = 1;
953                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
954                 }
955                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
956                 if (dsp) {
957                         /* don't need to watch for refcount zero and deleted, since
958                          * we haven't dropped the global lock.
959                          */
960                         dsp->refCount--;
961                         ++smb_dirSearchCounter;
962                         continue;
963                 }
964                 
965                 dsp = malloc(sizeof(*dsp));
966                 memset(dsp, 0, sizeof(*dsp));
967                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
968                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
969                 dsp->cookie = smb_dirSearchCounter;
970                 ++smb_dirSearchCounter;
971                 dsp->refCount = 1;
972                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
973                 dsp->lastTime = osi_Time();
974                 break;
975         }
976         lock_ReleaseWrite(&smb_globalLock);
977         return dsp;
978 }
979
980 static smb_packet_t *GetPacket(void)
981 {
982         smb_packet_t *tbp;
983         lock_ObtainWrite(&smb_globalLock);
984         tbp = smb_packetFreeListp;
985         if (tbp) smb_packetFreeListp = tbp->nextp;
986         lock_ReleaseWrite(&smb_globalLock);
987         if (!tbp) {
988                 tbp = GlobalAlloc(GMEM_FIXED, 65540);
989                 tbp->magic = SMB_PACKETMAGIC;
990                 tbp->ncbp = NULL;
991                 tbp->vcp = NULL;
992                 tbp->resumeCode = 0;
993                 tbp->inCount = 0;
994                 tbp->fid = 0;
995                 tbp->wctp = NULL;
996                 tbp->inCom = 0;
997                 tbp->oddByte = 0;
998                 tbp->ncb_length = 0;
999                 tbp->flags = 0;
1000         }
1001         
1002         osi_assert(tbp->magic == SMB_PACKETMAGIC);
1003
1004         return tbp;
1005 }
1006
1007 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1008 {
1009         smb_packet_t *tbp;
1010         tbp = GetPacket();
1011         memcpy(tbp, pkt, sizeof(smb_packet_t));
1012         tbp->wctp = tbp->data + (pkt->wctp - pkt->data);
1013         return tbp;
1014 }
1015
1016 static NCB *GetNCB(void)
1017 {
1018         smb_ncb_t *tbp;
1019         lock_ObtainWrite(&smb_globalLock);
1020         tbp = smb_ncbFreeListp;
1021         if (tbp) smb_ncbFreeListp = tbp->nextp;
1022         lock_ReleaseWrite(&smb_globalLock);
1023         if (!tbp) {
1024                 tbp = GlobalAlloc(GMEM_FIXED, sizeof(*tbp));
1025                 tbp->magic = SMB_NCBMAGIC;
1026         }
1027         
1028         osi_assert(tbp->magic == SMB_NCBMAGIC);
1029
1030         memset(&tbp->ncb, 0, sizeof(NCB));
1031         return &tbp->ncb;
1032 }
1033
1034 void smb_FreePacket(smb_packet_t *tbp)
1035 {
1036         osi_assert(tbp->magic == SMB_PACKETMAGIC);
1037         
1038         lock_ObtainWrite(&smb_globalLock);
1039         tbp->nextp = smb_packetFreeListp;
1040         smb_packetFreeListp = tbp;
1041         tbp->magic = SMB_PACKETMAGIC;
1042         tbp->ncbp = NULL;
1043         tbp->vcp = NULL;
1044         tbp->resumeCode = 0;
1045         tbp->inCount = 0;
1046         tbp->fid = 0;
1047         tbp->wctp = NULL;
1048         tbp->inCom = 0;
1049         tbp->oddByte = 0;
1050         tbp->ncb_length = 0;
1051         tbp->flags = 0;
1052         lock_ReleaseWrite(&smb_globalLock);
1053 }
1054
1055 static void FreeNCB(NCB *bufferp)
1056 {
1057         smb_ncb_t *tbp;
1058         
1059         tbp = (smb_ncb_t *) bufferp;
1060         osi_assert(tbp->magic == SMB_NCBMAGIC);
1061         
1062         lock_ObtainWrite(&smb_globalLock);
1063         tbp->nextp = smb_ncbFreeListp;
1064         smb_ncbFreeListp = tbp;
1065         lock_ReleaseWrite(&smb_globalLock);
1066 }
1067
1068 /* get a ptr to the data part of a packet, and its count */
1069 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1070 {
1071         int parmBytes;
1072         int dataBytes;
1073         unsigned char *afterParmsp;
1074
1075         parmBytes = *smbp->wctp << 1;
1076         afterParmsp = smbp->wctp + parmBytes + 1;
1077         
1078         dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1079         if (nbytesp) *nbytesp = dataBytes;
1080         
1081         /* don't forget to skip the data byte count, since it follows
1082          * the parameters; that's where the "2" comes from below.
1083          */
1084         return (unsigned char *) (afterParmsp + 2);
1085 }
1086
1087 /* must set all the returned parameters before playing around with the
1088  * data region, since the data region is located past the end of the
1089  * variable number of parameters.
1090  */
1091 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1092 {
1093         unsigned char *afterParmsp;
1094
1095         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1096         
1097         *afterParmsp++ = dsize & 0xff;
1098         *afterParmsp = (dsize>>8) & 0xff;
1099 }
1100
1101 /* return the parm'th parameter in the smbp packet */
1102 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1103 {
1104         int parmCount;
1105         unsigned char *parmDatap;
1106
1107         parmCount = *smbp->wctp;
1108
1109         if (parm >= parmCount) {
1110                 HANDLE h;
1111                 char *ptbuf[1];
1112                 char s[100];
1113                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1114                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1115                         parm, parmCount, smbp->ncb_length);
1116                 ptbuf[0] = s;
1117                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1118                             1, smbp->ncb_length, ptbuf, smbp);
1119                 DeregisterEventSource(h);
1120                 osi_panic(s, __FILE__, __LINE__);
1121         }
1122         parmDatap = smbp->wctp + (2*parm) + 1;
1123         
1124         return parmDatap[0] + (parmDatap[1] << 8);
1125 }
1126
1127 /* return the parm'th parameter in the smbp packet */
1128 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1129 {
1130         int parmCount;
1131         unsigned char *parmDatap;
1132
1133         parmCount = *smbp->wctp;
1134
1135         if (parm * 2 + offset >= parmCount * 2) {
1136                 HANDLE h;
1137                 char *ptbuf[1];
1138                 char s[100];
1139                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1140                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1141                         parm, offset, parmCount, smbp->ncb_length);
1142                 ptbuf[0] = s;
1143                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1144                             1, smbp->ncb_length, ptbuf, smbp);
1145                 DeregisterEventSource(h);
1146                 osi_panic(s, __FILE__, __LINE__);
1147         }
1148         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1149         
1150         return parmDatap[0] + (parmDatap[1] << 8);
1151 }
1152
1153 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1154 {
1155         char *parmDatap;
1156
1157         /* make sure we have enough slots */
1158         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1159         
1160         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1161         *parmDatap++ = parmValue & 0xff;
1162         *parmDatap = (parmValue>>8) & 0xff;
1163 }
1164
1165 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1166 {
1167         char *parmDatap;
1168
1169         /* make sure we have enough slots */
1170         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1171
1172         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1173         *parmDatap++ = parmValue & 0xff;
1174         *parmDatap++ = (parmValue>>8) & 0xff;
1175         *parmDatap++ = (parmValue>>16) & 0xff;
1176         *parmDatap++ = (parmValue>>24) & 0xff;
1177 }
1178
1179 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1180 {
1181         char *parmDatap;
1182         int i;
1183
1184         /* make sure we have enough slots */
1185         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1186
1187         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1188         for (i=0; i<8; i++)
1189                 *parmDatap++ = *parmValuep++;
1190 }
1191
1192 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1193 {
1194         char *parmDatap;
1195
1196         /* make sure we have enough slots */
1197         if (*smbp->wctp <= slot) {
1198                 if (smbp->oddByte) {
1199                         smbp->oddByte = 0;
1200                         *smbp->wctp = slot+1;
1201                 } else
1202                         smbp->oddByte = 1;
1203         }
1204
1205         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1206         *parmDatap++ = parmValue & 0xff;
1207 }
1208
1209 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1210 {
1211         char *lastSlashp;
1212         
1213         lastSlashp = strrchr(inPathp, '\\');
1214         if (lastComponentp)
1215                 *lastComponentp = lastSlashp;
1216         if (lastSlashp) {
1217                 while (1) {
1218                         if (inPathp == lastSlashp) break;
1219                         *outPathp++ = *inPathp++;
1220                 }
1221                 *outPathp++ = 0;
1222         }
1223         else {
1224                 *outPathp++ = 0;
1225         }
1226 }
1227
1228 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1229 {
1230         if (*inp++ != 0x4) return NULL;
1231         if (chainpp) {
1232                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1233         }
1234         return inp;
1235 }
1236
1237 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1238 {
1239         int tlen;
1240
1241         if (*inp++ != 0x5) return NULL;
1242         tlen = inp[0] + (inp[1]<<8);
1243         inp += 2;               /* skip length field */
1244         
1245         if (chainpp) {
1246                 *chainpp = inp + tlen;
1247         }
1248         
1249         if (lengthp) *lengthp = tlen;
1250         
1251         return inp;
1252 }
1253
1254 /* format a packet as a response */
1255 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1256 {
1257         smb_t *outp;
1258         smb_t *inSmbp;
1259
1260         outp = (smb_t *) op;
1261         
1262         /* zero the basic structure through the smb_wct field, and zero the data
1263          * size field, assuming that wct stays zero; otherwise, you have to 
1264          * explicitly set the data size field, too.
1265          */
1266         inSmbp = (smb_t *) inp;
1267         memset(outp, 0, sizeof(smb_t)+2);
1268         outp->id[0] = 0xff;
1269         outp->id[1] = 'S';
1270         outp->id[2] = 'M';
1271         outp->id[3] = 'B';
1272         if (inp) {
1273                 outp->com = inSmbp->com;
1274                 outp->tid = inSmbp->tid;
1275                 outp->pid = inSmbp->pid;
1276                 outp->uid = inSmbp->uid;
1277                 outp->mid = inSmbp->mid;
1278                 outp->res[0] = inSmbp->res[0];
1279                 outp->res[1] = inSmbp->res[1];
1280                 op->inCom = inSmbp->com;
1281         }
1282         outp->reb = 0x80;       /* SERVER_RESP */
1283         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1284
1285         /* copy fields in generic packet area */
1286         op->wctp = &outp->wct;
1287 }
1288
1289 /* send a (probably response) packet; vcp tells us to whom to send it.
1290  * we compute the length by looking at wct and bcc fields.
1291  */
1292 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1293 {
1294         NCB *ncbp;
1295         int extra;
1296         long code;
1297         unsigned char *tp;
1298         int localNCB = 0;
1299         
1300         ncbp = inp->ncbp;
1301         if (ncbp == NULL) {
1302                 ncbp = GetNCB();
1303                 localNCB = 1;
1304         }
1305         memset((char *)ncbp, 0, sizeof(NCB));
1306
1307         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
1308         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
1309         extra += tp[0] + (tp[1]<<8);
1310         extra += (inp->wctp - inp->data);       /* distance to last wct field */
1311         extra += 3;                     /* wct and length fields */
1312         
1313         ncbp->ncb_length = extra;       /* bytes to send */
1314         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
1315         ncbp->ncb_lana_num = smb_LANadapter;
1316         ncbp->ncb_command = NCBSEND;    /* op means send data */
1317         ncbp->ncb_buffer = (char *) inp;/* packet */
1318         
1319         code = Netbios(ncbp);
1320         if (code != 0)
1321                 osi_Log1(afsd_logp, "SendPacket failure code %d", code);
1322
1323         if (localNCB)
1324                 FreeNCB(ncbp);
1325 }
1326
1327 void smb_MapNTError(long code, unsigned long *NTStatusp)
1328 {
1329         unsigned long NTStatus;
1330
1331         /* map CM_ERROR_* errors to NT 32-bit status codes */
1332         if (code == CM_ERROR_NOSUCHCELL) {
1333                 NTStatus = 0xC000000FL; /* No such file */
1334         }
1335         else if (code == CM_ERROR_NOSUCHVOLUME) {
1336                 NTStatus = 0xC000000FL; /* No such file */
1337         }
1338         else if (code == CM_ERROR_TIMEDOUT) {
1339                 NTStatus = 0xC00000CFL; /* Paused */
1340         }
1341         else if (code == CM_ERROR_RETRY) {
1342                 NTStatus = 0xC000022DL; /* Retry */
1343         }
1344         else if (code == CM_ERROR_NOACCESS) {
1345                 NTStatus = 0xC0000022L; /* Access denied */
1346         }
1347         else if (code == CM_ERROR_READONLY) {
1348                 NTStatus = 0xC00000A2L; /* Write protected */
1349         }
1350         else if (code == CM_ERROR_NOSUCHFILE) {
1351                 NTStatus = 0xC000000FL; /* No such file */
1352         }
1353         else if (code == CM_ERROR_NOSUCHPATH) {
1354                 NTStatus = 0xC000003AL; /* Object path not found */
1355         }
1356         else if (code == CM_ERROR_TOOBIG) {
1357                 NTStatus = 0xC000007BL; /* Invalid image format */
1358         }
1359         else if (code == CM_ERROR_INVAL) {
1360                 NTStatus = 0xC000000DL; /* Invalid parameter */
1361         }
1362         else if (code == CM_ERROR_BADFD) {
1363                 NTStatus = 0xC0000008L; /* Invalid handle */
1364         }
1365         else if (code == CM_ERROR_BADFDOP) {
1366                 NTStatus = 0xC0000022L; /* Access denied */
1367         }
1368         else if (code == CM_ERROR_EXISTS) {
1369                 NTStatus = 0xC0000035L; /* Object name collision */
1370         }
1371         else if (code == CM_ERROR_NOTEMPTY) {
1372                 NTStatus = 0xC0000101L; /* Directory not empty */
1373         }
1374         else if (code == CM_ERROR_CROSSDEVLINK) {
1375                 NTStatus = 0xC00000D4L; /* Not same device */
1376         }
1377         else if (code == CM_ERROR_NOTDIR) {
1378                 NTStatus = 0xC0000103L; /* Not a directory */
1379         }
1380         else if (code == CM_ERROR_ISDIR) {
1381                 NTStatus = 0xC00000BAL; /* File is a directory */
1382         }
1383         else if (code == CM_ERROR_BADOP) {
1384                 NTStatus = 0xC09820FFL; /* SMB no support */
1385         }
1386         else if (code == CM_ERROR_BADSHARENAME) {
1387                 NTStatus = 0xC00000CCL; /* Bad network name */
1388         }
1389         else if (code == CM_ERROR_NOIPC) {
1390                 NTStatus = 0xC00000CCL; /* Bad network name */
1391         }
1392         else if (code == CM_ERROR_CLOCKSKEW) {
1393                 NTStatus = 0xC0000133L; /* Time difference at DC */
1394         }
1395         else if (code == CM_ERROR_BADTID) {
1396                 NTStatus = 0xC0982005L; /* SMB bad TID */
1397         }
1398         else if (code == CM_ERROR_USESTD) {
1399                 NTStatus = 0xC09820FBL; /* SMB use standard */
1400         }
1401         else if (code == CM_ERROR_QUOTA) {
1402                 NTStatus = 0xC0000044L; /* Quota exceeded */
1403         }
1404         else if (code == CM_ERROR_SPACE) {
1405                 NTStatus = 0xC000007FL; /* Disk full */
1406         }
1407         else if (code == CM_ERROR_ATSYS) {
1408                 NTStatus = 0xC0000033L; /* Object name invalid */
1409         }
1410         else if (code == CM_ERROR_BADNTFILENAME) {
1411                 NTStatus = 0xC0000033L; /* Object name invalid */
1412         }
1413         else if (code == CM_ERROR_WOULDBLOCK) {
1414                 NTStatus = 0xC0000055L; /* Lock not granted */
1415         }
1416         else if (code == CM_ERROR_PARTIALWRITE) {
1417                 NTStatus = 0xC000007FL; /* Disk full */
1418         }
1419         else if (code == CM_ERROR_BUFFERTOOSMALL) {
1420                 NTStatus = 0xC0000023L; /* Buffer too small */
1421         }
1422         else {
1423                 NTStatus = 0xC0982001L; /* SMB non-specific error */
1424         }
1425
1426         *NTStatusp = NTStatus;
1427         osi_Log2(afsd_logp, "SMB SEND code %x as NT %x", code, NTStatus);
1428 }
1429
1430 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
1431         unsigned char *classp)
1432 {
1433         unsigned char class;
1434         unsigned short error;
1435
1436         /* map CM_ERROR_* errors to SMB errors */
1437         if (code == CM_ERROR_NOSUCHCELL) {
1438                 class = 1;
1439                 error = 3;      /* bad path */
1440         }
1441         else if (code == CM_ERROR_NOSUCHVOLUME) {
1442                 class = 1;
1443                 error = 3;      /* bad path */
1444         }
1445         else if (code == CM_ERROR_TIMEDOUT) {
1446                 class = 2;
1447                 error = 81;     /* server is paused */
1448         }
1449         else if (code == CM_ERROR_RETRY) {
1450                 class = 2;      /* shouldn't happen */
1451                 error = 1;
1452         }
1453         else if (code == CM_ERROR_NOACCESS) {
1454                 class = 2;
1455                 error = 4;      /* bad access */
1456         }
1457         else if (code == CM_ERROR_READONLY) {
1458                 class = 3;
1459                 error = 19;     /* read only */
1460         }
1461         else if (code == CM_ERROR_NOSUCHFILE) {
1462                 class = 1;
1463                 error = 2;      /* ENOENT! */
1464         }
1465         else if (code == CM_ERROR_NOSUCHPATH) {
1466                 class = 1;
1467                 error = 3;      /* Bad path */
1468         }
1469         else if (code == CM_ERROR_TOOBIG) {
1470                 class = 1;
1471                 error = 11;     /* bad format */
1472         }
1473         else if (code == CM_ERROR_INVAL) {
1474                 class = 2;      /* server non-specific error code */
1475                 error = 1;
1476         }
1477         else if (code == CM_ERROR_BADFD) {
1478                 class = 1;
1479                 error = 6;      /* invalid file handle */
1480         }
1481         else if (code == CM_ERROR_BADFDOP) {
1482                 class = 1;      /* invalid op on FD */
1483                 error = 5;
1484         }
1485         else if (code == CM_ERROR_EXISTS) {
1486                 class = 1;
1487                 error = 80;     /* file already exists */
1488         }
1489         else if (code == CM_ERROR_NOTEMPTY) {
1490                 class = 1;
1491                 error = 5;      /* delete directory not empty */
1492         }
1493         else if (code == CM_ERROR_CROSSDEVLINK) {
1494                 class = 1;
1495                 error = 17;     /* EXDEV */
1496         }
1497         else if (code == CM_ERROR_NOTDIR) {
1498                 class = 1;      /* bad path */
1499                 error = 3;
1500         }
1501         else if (code == CM_ERROR_ISDIR) {
1502                 class = 1;      /* access denied; DOS doesn't have a good match */
1503                 error = 5;
1504         }
1505         else if (code == CM_ERROR_BADOP) {
1506                 class = 2;
1507                 error = 65535;
1508         }
1509         else if (code == CM_ERROR_BADSHARENAME) {
1510                 class = 2;
1511                 error = 6;
1512         }
1513         else if (code == CM_ERROR_NOIPC) {
1514                 class = 1;
1515                 error = 66;
1516         }
1517         else if (code == CM_ERROR_CLOCKSKEW) {
1518                 class = 1;      /* invalid function */
1519                 error = 1;
1520         }
1521         else if (code == CM_ERROR_BADTID) {
1522                 class = 2;
1523                 error = 5;
1524         }
1525         else if (code == CM_ERROR_USESTD) {
1526                 class = 2;
1527                 error = 251;
1528         }
1529         else if (code == CM_ERROR_REMOTECONN) {
1530                 class = 2;
1531                 error = 82;
1532         }
1533         else if (code == CM_ERROR_QUOTA) {
1534                 if (vcp->flags & SMB_VCFLAG_USEV3) {
1535                         class = 3;
1536                         error = 39;     /* disk full */
1537                 }
1538                 else {
1539                         class = 1;
1540                         error = 5;      /* access denied */
1541                 }
1542         }
1543         else if (code == CM_ERROR_SPACE) {
1544                 if (vcp->flags & SMB_VCFLAG_USEV3) {
1545                         class = 3;
1546                         error = 39;     /* disk full */
1547                 }
1548                 else {
1549                         class = 1;
1550                         error = 5;      /* access denied */
1551                 }
1552         }
1553         else if (code == CM_ERROR_PARTIALWRITE) {
1554                 class = 3;
1555                 error = 39;     /* disk full */
1556         }
1557         else if (code == CM_ERROR_ATSYS) {
1558                 class = 1;
1559                 error = 2;      /* ENOENT */
1560         }
1561         else if (code == CM_ERROR_WOULDBLOCK) {
1562                 class = 1;
1563                 error = 33;     /* lock conflict */
1564         }
1565         else if (code == CM_ERROR_NOFILES) {
1566                 class = 1;
1567                 error = 18;     /* no files in search */
1568         }
1569         else {
1570                 class = 2;
1571                 error = 1;
1572         }
1573
1574         *scodep = error;
1575         *classp = class;
1576         osi_Log3(afsd_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
1577 }
1578
1579 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1580 {
1581         return CM_ERROR_BADOP;
1582 }
1583
1584 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1585 {
1586         unsigned short EchoCount, i;
1587         char *data, *outdata;
1588         int dataSize;
1589
1590         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
1591
1592         for (i=1; i<=EchoCount; i++) {
1593             data = smb_GetSMBData(inp, &dataSize);
1594             smb_SetSMBParm(outp, 0, i);
1595             smb_SetSMBDataLength(outp, dataSize);
1596             outdata = smb_GetSMBData(outp, NULL);
1597             memcpy(outdata, data, dataSize);
1598             smb_SendPacket(vcp, outp);
1599         }
1600
1601         return 0;
1602 }
1603
1604 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1605 {
1606         osi_hyper_t offset;
1607         long count, minCount, finalCount;
1608         unsigned short fd;
1609         smb_fid_t *fidp;
1610         long code;
1611         cm_user_t *userp = NULL;
1612         char *rawBuf;
1613         NCB *ncbp;
1614
1615         rawBuf = NULL;
1616         finalCount = 0;
1617
1618         fd = smb_GetSMBParm(inp, 0);
1619         count = smb_GetSMBParm(inp, 3);
1620         minCount = smb_GetSMBParm(inp, 4);
1621         offset.HighPart = 0;    /* too bad */
1622         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
1623
1624         osi_Log3(afsd_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
1625                  fd, offset.LowPart, count);
1626
1627         fidp = smb_FindFID(vcp, fd, 0);
1628         if (!fidp)
1629                 goto send1;
1630
1631         if (fidp->flags & SMB_FID_IOCTL)
1632                 return smb_IoctlReadRaw(fidp, vcp, inp, outp);
1633
1634         userp = smb_GetUser(vcp, inp);
1635
1636         lock_ObtainMutex(&smb_RawBufLock);
1637         if (smb_RawBufs) {
1638                 /* Get a raw buf, from head of list */
1639                 rawBuf = smb_RawBufs;
1640                 smb_RawBufs = *(char **)smb_RawBufs;
1641         }
1642         lock_ReleaseMutex(&smb_RawBufLock);
1643         if (!rawBuf)
1644                 goto send;
1645
1646         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
1647         if (code != 0)
1648                 goto send;
1649
1650 send:
1651         smb_ReleaseFID(fidp);
1652
1653         cm_ReleaseUser(userp);
1654 send1:
1655         ncbp = outp->ncbp;
1656         memset((char *)ncbp, 0, sizeof(NCB));
1657
1658         ncbp->ncb_length = (unsigned short) finalCount;
1659         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
1660         ncbp->ncb_lana_num = smb_LANadapter;
1661         ncbp->ncb_command = NCBSEND;
1662         ncbp->ncb_buffer = rawBuf;
1663
1664         code = Netbios(ncbp);
1665         if (code != 0)
1666                 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
1667
1668         if (rawBuf) {
1669                 /* Give back raw buffer */
1670                 lock_ObtainMutex(&smb_RawBufLock);
1671                 *((char **) rawBuf) = smb_RawBufs;
1672                 smb_RawBufs = rawBuf;
1673                 lock_ReleaseMutex(&smb_RawBufLock);
1674         }
1675
1676         return 0;
1677 }
1678
1679 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1680 {
1681         return 0;
1682 }
1683
1684 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1685 {
1686         return 0;
1687 }
1688
1689 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1690 {
1691         char *namep;
1692         int coreProtoIndex;
1693         int v3ProtoIndex;
1694         int NTProtoIndex;
1695         int protoIndex;                 /* index we're using */
1696         int namex;
1697         long dbytes;
1698         int entryLength;
1699         int tcounter;
1700         char protocol_array[10][1024]; /* protocol signature of the client */
1701
1702         
1703         osi_Log1(afsd_logp, "SMB receive negotiate; %d + 1 ongoing ops",
1704                  ongoingOps - 1);
1705         if (!isGateway) {
1706                 if (active_vcp) {
1707                         DWORD now = GetCurrentTime();
1708                         if (now - last_msg_time >= 30000
1709                               && now - last_msg_time <= 90000) {
1710                                 osi_Log1(afsd_logp,
1711                                          "Setting dead_vcp %x", active_vcp);
1712                                 dead_vcp = active_vcp;
1713                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
1714                         }
1715                 }
1716         }
1717
1718         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
1719
1720         namep = smb_GetSMBData(inp, &dbytes);
1721         namex = 0;
1722         tcounter = 0;
1723         coreProtoIndex = -1;            /* not found */
1724         v3ProtoIndex = -1;
1725         NTProtoIndex = -1;
1726         while(namex < dbytes) {
1727                 osi_Log1(afsd_logp, "Protocol %s",
1728                          osi_LogSaveString(afsd_logp, namep+1));
1729                 strcpy(protocol_array[tcounter], namep+1);
1730
1731                 /* namep points at the first protocol, or really, a 0x02
1732                  * byte preceding the null-terminated ASCII name.
1733                  */
1734                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
1735                         coreProtoIndex = tcounter;
1736                 }
1737                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
1738                         v3ProtoIndex = tcounter;
1739                 }
1740                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
1741                         NTProtoIndex = tcounter;
1742                 }
1743
1744                 /* compute size of protocol entry */
1745                 entryLength = strlen(namep+1);
1746                 entryLength += 2;       /* 0x02 bytes and null termination */
1747                 
1748                 /* advance over this protocol entry */
1749                 namex += entryLength;
1750                 namep += entryLength;
1751                 tcounter++;             /* which proto entry we're looking at */
1752         }
1753         /* 
1754          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
1755          * the client is running by reading the protocol signature.
1756          * ie. the order in which it sends us the protocol list.
1757          *
1758          * Special handling for Windows 2000 clients (defect 11765 )
1759          */
1760         if (tcounter == 6) {
1761                int i = 0;
1762                smb_t *ip = (smb_t *) inp;
1763                smb_t *op = (smb_t *) outp;
1764
1765                if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
1766                    (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
1767                    (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
1768                    (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
1769                    (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
1770                    (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
1771                       isWindows2000 = TRUE;
1772                       osi_Log0(afsd_logp, "Looks like a Windows 2000 client");
1773                       /* 
1774                        * HACK: for now - just negotiate a lower protocol till we 
1775                        * figure out which flag/flag2 or some other field 
1776                        * (capabilities maybe?) to set in order for this to work
1777                        * correctly with Windows 2000 clients (defect 11765)
1778                        */
1779                       NTProtoIndex = -1;
1780                       /* Things to try (after looking at tcpdump output could be
1781                        * setting flags and flags2 to 0x98 and 0xc853 like this
1782                        * op->reb = 0x98; op->flg2 = 0xc853;
1783                        * osi_Log2(afsd_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
1784                        */
1785                }
1786         }
1787
1788         if (NTProtoIndex != -1) {
1789                 protoIndex = NTProtoIndex;
1790                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
1791         }
1792         else if (v3ProtoIndex != -1) {
1793                 protoIndex = v3ProtoIndex;
1794                 vcp->flags |= SMB_VCFLAG_USEV3;
1795         }
1796         else if (coreProtoIndex != -1) {
1797                 protoIndex = coreProtoIndex;
1798                 vcp->flags |= SMB_VCFLAG_USECORE;
1799         }
1800         else protoIndex = -1;
1801
1802         if (protoIndex == -1)
1803                 return CM_ERROR_INVAL;
1804         else if (NTProtoIndex != -1) {
1805                 smb_SetSMBParm(outp, 0, protoIndex);
1806                 smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
1807                 smb_SetSMBParm(outp, 1, 8);     /* max multiplexed requests */
1808                 smb_SetSMBParm(outp, 2, 100);   /* max VCs per consumer/server connection */
1809                 smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
1810                 smb_SetSMBParmLong(outp, 5, 65536);     /* raw buffer size */
1811                 smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
1812                 smb_SetSMBParm(outp, 8, 1);
1813                 /* 
1814                  * Tried changing the capabilities to support for W2K - defect 117695
1815                  * Maybe something else needs to be changed here?
1816                  */
1817                 /*
1818                   if (isWindows2000) 
1819                   smb_SetSMBParmLong(outp, 9, 0x43fd);
1820                   else 
1821                   smb_SetSMBParmLong(outp, 9, 0x251);
1822                   */
1823                 smb_SetSMBParmLong(outp, 9, 0x251);     /* Capabilities: *
1824                                                  * 32-bit error codes *
1825                                                  * and NT Find *
1826                                                  * and NT SMB's *
1827                                                  * and raw mode */
1828                 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
1829                 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
1830                 smb_SetSMBParm(outp, 15, 0);    /* XXX server tzone: do we need? */
1831                 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
1832                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
1833         }
1834         else if (v3ProtoIndex != -1) {
1835                 smb_SetSMBParm(outp, 0, protoIndex);
1836                 smb_SetSMBParm(outp, 1, 0);     /* share level security, no passwd encrypt */
1837                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
1838                 smb_SetSMBParm(outp, 3, 8);     /* max multiplexed requests */
1839                 smb_SetSMBParm(outp, 4, 100);   /* max VCs per consumer/server connection */
1840                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
1841                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
1842                 smb_SetSMBParm(outp, 7, 1);
1843                 smb_SetSMBParm(outp, 8, 0);     /* XXX server time: do we need? */
1844                 smb_SetSMBParm(outp, 9, 0);     /* XXX server date: do we need? */
1845                 smb_SetSMBParm(outp, 10, 0);    /* XXX server tzone: do we need? */
1846                 smb_SetSMBParm(outp, 11, 0);    /* resvd */
1847                 smb_SetSMBParm(outp, 12, 0);    /* resvd */
1848                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
1849         }
1850         else if (coreProtoIndex != -1) {
1851                 smb_SetSMBParm(outp, 0, protoIndex);
1852                 smb_SetSMBDataLength(outp, 0);
1853         }
1854         return 0;
1855 }
1856
1857 void smb_Daemon(void *parmp)
1858 {
1859         int count = 0;
1860
1861         while(1) {
1862                 count++;
1863                 Sleep(10000);
1864                 if ((count % 360) == 0)         /* every hour */
1865                         smb_CalculateNowTZ();
1866                 /* XXX GC dir search entries */
1867         }
1868 }
1869
1870 void smb_WaitingLocksDaemon()
1871 {
1872         smb_waitingLock_t *wL, *nwL;
1873         int first;
1874         smb_vc_t *vcp;
1875         smb_packet_t *inp, *outp;
1876         NCB *ncbp;
1877         long code;
1878
1879         while(1) {
1880                 lock_ObtainWrite(&smb_globalLock);
1881                 nwL = smb_allWaitingLocks;
1882                 if (nwL == NULL) {
1883                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
1884                         Sleep(1000);
1885                         continue;
1886                 }
1887                 else first = 1;
1888                 do {
1889                         if (first)
1890                                 first = 0;
1891                         else
1892                                 lock_ObtainWrite(&smb_globalLock);
1893                         wL = nwL;
1894                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
1895                         lock_ReleaseWrite(&smb_globalLock);
1896                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
1897                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
1898                         if (code == CM_ERROR_WOULDBLOCK) {
1899                                 /* no progress */
1900                                 if (wL->timeRemaining != 0xffffffff
1901                                     && (wL->timeRemaining -= 1000) < 0)
1902                                         goto endWait;
1903                                 continue;
1904                         }
1905 endWait:
1906                         vcp = wL->vcp;
1907                         inp = wL->inp;
1908                         outp = wL->outp;
1909                         ncbp = GetNCB();
1910                         ncbp->ncb_length = inp->ncb_length;
1911                         inp->spacep = cm_GetSpace();
1912
1913                         /* Remove waitingLock from list */
1914                         lock_ObtainWrite(&smb_globalLock);
1915                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
1916                                     &wL->q);
1917                         lock_ReleaseWrite(&smb_globalLock);
1918
1919                         /* Resume packet processing */
1920                         if (code == 0)
1921                                 smb_SetSMBDataLength(outp, 0);
1922                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
1923                         outp->resumeCode = code;
1924                         outp->ncbp = ncbp;
1925                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
1926
1927                         /* Clean up */
1928                         cm_FreeSpace(inp->spacep);
1929                         smb_FreePacket(inp);
1930                         smb_FreePacket(outp);
1931                         FreeNCB(ncbp);
1932                         free(wL);
1933                 } while (nwL);
1934                 Sleep(1000);
1935         }
1936 }
1937
1938 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
1939 {
1940         osi_Log0(afsd_logp, "SMB receive get disk attributes");
1941
1942         smb_SetSMBParm(outp, 0, 32000);
1943         smb_SetSMBParm(outp, 1, 64);
1944         smb_SetSMBParm(outp, 2, 1024);
1945         smb_SetSMBParm(outp, 3, 30000);
1946         smb_SetSMBParm(outp, 4, 0);
1947         smb_SetSMBDataLength(outp, 0);
1948         return 0;
1949 }
1950
1951 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
1952 {
1953         smb_tid_t *tidp;
1954         unsigned short newTid;
1955         char shareName[256];
1956         char *sharePath;
1957         int shareFound;
1958         char *tp;
1959         char *pathp;
1960         char *passwordp;
1961         cm_user_t *userp;
1962         
1963         osi_Log0(afsd_logp, "SMB receive tree connect");
1964
1965         /* parse input parameters */
1966         tp = smb_GetSMBData(inp, NULL);
1967         pathp = smb_ParseASCIIBlock(tp, &tp);
1968         passwordp = smb_ParseASCIIBlock(tp, &tp);
1969         tp = strrchr(pathp, '\\');
1970         if (!tp)
1971                 return CM_ERROR_BADSMB;
1972         strcpy(shareName, tp+1);
1973
1974         userp = smb_GetUser(vcp, inp);
1975
1976         lock_ObtainMutex(&vcp->mx);
1977         newTid = vcp->tidCounter++;
1978         lock_ReleaseMutex(&vcp->mx);
1979         
1980         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
1981         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
1982         if (!shareFound) {
1983                 smb_ReleaseTID(tidp);
1984                 return CM_ERROR_BADSHARENAME;
1985         }
1986         lock_ObtainMutex(&tidp->mx);
1987         tidp->userp = userp;
1988         tidp->pathname = sharePath;
1989         lock_ReleaseMutex(&tidp->mx);
1990         smb_ReleaseTID(tidp);
1991
1992         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
1993         smb_SetSMBParm(rsp, 1, newTid);
1994         smb_SetSMBDataLength(rsp, 0);
1995         
1996         osi_Log1(afsd_logp, "SMB tree connect created ID %d", newTid);
1997         return 0;
1998 }
1999
2000 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2001 {
2002         int tlen;
2003
2004         if (*inp++ != 0x1) return NULL;
2005         tlen = inp[0] + (inp[1]<<8);
2006         inp += 2;               /* skip length field */
2007         
2008         if (chainpp) {
2009                 *chainpp = inp + tlen;
2010         }
2011         
2012         if (lengthp) *lengthp = tlen;
2013         
2014         return inp;
2015 }
2016
2017 /* set maskp to the mask part of the incoming path.
2018  * Mask is 11 bytes long (8.3 with the dot elided).
2019  * Returns true if succeeds with a valid name, otherwise it does
2020  * its best, but returns false.
2021  */
2022 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2023 {
2024         char *tp;
2025         char *up;
2026         int i;
2027         int tc;
2028         int valid8Dot3;
2029
2030         /* starts off valid */
2031         valid8Dot3 = 1;
2032
2033         /* mask starts out all blanks */
2034         memset(maskp, ' ', 11);
2035
2036         /* find last backslash, or use whole thing if there is none */
2037         tp = strrchr(pathp, '\\');
2038         if (!tp) tp = pathp;
2039         else tp++;      /* skip slash */
2040         
2041         up = maskp;
2042
2043         /* names starting with a dot are illegal */
2044         if (*tp == '.') valid8Dot3 = 0;
2045
2046         for(i=0;; i++) {
2047                 tc = *tp++;
2048                 if (tc == 0) return valid8Dot3;
2049                 if (tc == '.' || tc == '"') break;
2050                 if (i < 8) *up++ = tc;
2051                 else valid8Dot3 = 0;
2052         }
2053         
2054         /* if we get here, tp point after the dot */
2055         up = maskp+8;   /* ext goes here */
2056         for(i=0;;i++) {
2057                 tc = *tp++;
2058                 if (tc == 0) return valid8Dot3;
2059                 
2060                 /* too many dots */
2061                 if (tc == '.' || tc == '"') valid8Dot3 = 0;
2062
2063                 /* copy extension if not too long */
2064                 if (i < 3) *up++ = tc;
2065                 else valid8Dot3 = 0;
2066         }
2067 }
2068
2069 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2070 {
2071         char umask[11];
2072         int valid;
2073         int i;
2074         char tc1;
2075         char tc2;
2076         char *tp1;
2077         char *tp2;
2078         
2079         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2080
2081         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2082         if (!valid) return 0;
2083  
2084         /* otherwise, we have a valid 8.3 name; see if we have a match,
2085          * treating '?' as a wildcard in maskp (but not in the file name).
2086          */
2087         tp1 = umask;    /* real name, in mask format */
2088         tp2 = maskp;    /* mask, in mask format */
2089         for(i=0; i<11; i++) {
2090                 tc1 = *tp1++;   /* char from real name */
2091                 tc2 = *tp2++;   /* char from mask */
2092                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2093                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2094                 if (tc1 == tc2) continue;
2095                 if (tc2 == '?' && tc1 != ' ') continue;
2096                 if (tc2 == '>') continue;
2097                 return 0;
2098         }
2099
2100         /* we got a match */
2101         return 1;
2102 }
2103
2104 char *smb_FindMask(char *pathp)
2105 {
2106         char *tp;
2107         
2108         tp = strrchr(pathp, '\\');      /* find last slash */
2109
2110         if (tp) return tp+1;    /* skip the slash */
2111         else return pathp;      /* no slash, return the entire path */
2112 }
2113
2114 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2115 {
2116         unsigned char *pathp;
2117         unsigned char *tp;
2118         unsigned char mask[11];
2119         unsigned char *statBlockp;
2120         unsigned char initStatBlock[21];
2121         int statLen;
2122         
2123         osi_Log0(afsd_logp, "SMB receive search volume");
2124
2125         /* pull pathname and stat block out of request */
2126         tp = smb_GetSMBData(inp, NULL);
2127         pathp = smb_ParseASCIIBlock(tp, &tp);
2128         osi_assert(pathp != NULL);
2129         statBlockp = smb_ParseVblBlock(tp, &tp, &statLen);
2130         osi_assert(statBlockp != NULL);
2131         if (statLen == 0) {
2132                 statBlockp = initStatBlock;
2133                 statBlockp[0] = 8;
2134         }
2135         
2136         /* for returning to caller */
2137         smb_Get8Dot3MaskFromPath(mask, pathp);
2138         
2139         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
2140         tp = smb_GetSMBData(outp, NULL);
2141         *tp++ = 5;
2142         *tp++ = 43;     /* bytes in a dir entry */
2143         *tp++ = 0;      /* high byte in counter */
2144         
2145         /* now marshall the dir entry, starting with the search status */
2146         *tp++ = statBlockp[0];          /* Reserved */
2147         memcpy(tp, mask, 11); tp += 11; /* FileName */
2148
2149         /* now pass back server use info, with 1st byte non-zero */
2150         *tp++ = 1;
2151         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
2152         
2153         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
2154         
2155         *tp++ = 0x8;            /* attribute: volume */
2156
2157         /* copy out time */
2158         *tp++ = 0;
2159         *tp++ = 0;
2160         
2161         /* copy out date */
2162         *tp++ = 18;
2163         *tp++ = 178;
2164         
2165         /* 4 byte file size */
2166         *tp++ = 0;
2167         *tp++ = 0;
2168         *tp++ = 0;
2169         *tp++ = 0;
2170
2171         /* finally, null-terminated 8.3 pathname, which we set to AFS */
2172         memset(tp, ' ', 13);
2173         strcpy(tp, "AFS");
2174         
2175         /* set the length of the data part of the packet to 43 + 3, for the dir
2176          * entry plus the 5 and the length fields.
2177          */
2178         smb_SetSMBDataLength(outp, 46);
2179         return 0;
2180 }
2181
2182 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2183         cm_user_t *userp, cm_req_t *reqp)
2184 {
2185         long code;
2186         cm_scache_t *scp;
2187         char *dptr;
2188         long dosTime;
2189         u_short shortTemp;
2190         char attr;
2191         smb_dirListPatch_t *patchp;
2192         smb_dirListPatch_t *npatchp;
2193         
2194         for(patchp = *dirPatchespp; patchp; patchp =
2195                 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2196                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2197                 if (code) continue;
2198                 lock_ObtainMutex(&scp->mx);
2199                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2200                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2201                 if (code) {
2202                         lock_ReleaseMutex(&scp->mx);
2203                         cm_ReleaseSCache(scp);
2204                         continue;
2205                 }
2206                 dptr = patchp->dptr;
2207
2208                 attr = smb_Attributes(scp);
2209                 *dptr++ = attr;
2210
2211                 /* get dos time */
2212                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2213                 
2214                 /* copy out time */
2215                 shortTemp = dosTime & 0xffff;
2216                 *((u_short *)dptr) = shortTemp;
2217                 dptr += 2;
2218
2219                 /* and copy out date */
2220                 shortTemp = (dosTime>>16) & 0xffff;
2221                 *((u_short *)dptr) = shortTemp;
2222                 dptr += 2;
2223                 
2224                 /* copy out file length */
2225                 *((u_long *)dptr) = scp->length.LowPart;
2226                 dptr += 4;
2227                 lock_ReleaseMutex(&scp->mx);
2228                 cm_ReleaseSCache(scp);
2229         }
2230         
2231         /* now free the patches */
2232         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2233                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2234                 free(patchp);
2235         }
2236         
2237         /* and mark the list as empty */
2238         *dirPatchespp = NULL;
2239
2240         return code;
2241 }
2242
2243 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2244 {
2245         int attribute;
2246         long nextCookie;
2247         char *tp;
2248         long code;
2249         char *pathp;
2250         cm_dirEntry_t *dep;
2251         int maxCount;
2252         smb_dirListPatch_t *dirListPatchesp;
2253         smb_dirListPatch_t *curPatchp;
2254         long dataLength;
2255         cm_buf_t *bufferp;
2256         long temp;
2257         osi_hyper_t dirLength;
2258         osi_hyper_t bufferOffset;
2259         osi_hyper_t curOffset;
2260         osi_hyper_t thyper;
2261         unsigned char *inCookiep;
2262         smb_dirSearch_t *dsp;
2263         cm_scache_t *scp;
2264         long entryInDir;
2265         long entryInBuffer;
2266         unsigned long clientCookie;
2267         cm_pageHeader_t *pageHeaderp;
2268         cm_user_t *userp = NULL;
2269         int slotInPage;
2270         char shortName[13];
2271         char *actualName;
2272         char *shortNameEnd;
2273         char mask[11];
2274         int returnedNames;
2275         long nextEntryCookie;
2276         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
2277         char resByte;                   /* reserved byte from the cookie */
2278         char *op;                       /* output data ptr */
2279         char *origOp;                   /* original value of op */
2280         cm_space_t *spacep;             /* for pathname buffer */
2281         int starPattern;
2282         int rootPath = 0;
2283         int caseFold;
2284         char *tidPathp;
2285         cm_req_t req;
2286
2287         cm_InitReq(&req);
2288
2289         maxCount = smb_GetSMBParm(inp, 0);
2290
2291         dirListPatchesp = NULL;
2292         
2293         caseFold = CM_FLAG_CASEFOLD;
2294
2295         tp = smb_GetSMBData(inp, NULL);
2296         pathp = smb_ParseASCIIBlock(tp, &tp);
2297         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2298         
2299         /* bail out if request looks bad */
2300         if (!tp || !pathp) {
2301                 return CM_ERROR_BADSMB;
2302         }
2303
2304         /* We can handle long names */
2305         if (vcp->flags & SMB_VCFLAG_USENT)
2306                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
2307         
2308         /* make sure we got a whole search status */
2309         if (dataLength < 21) {
2310                 nextCookie = 0;         /* start at the beginning of the dir */
2311                 resByte = 0;
2312                 clientCookie = 0;
2313                 attribute = smb_GetSMBParm(inp, 1);
2314
2315                 /* handle volume info in another function */
2316                 if (attribute & 0x8)
2317                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2318
2319                 osi_Log2(afsd_logp, "SMB receive search dir count %d |%s|",
2320                          maxCount, osi_LogSaveString(afsd_logp, pathp));
2321
2322                 if (*pathp == 0) {      /* null pathp, treat as root dir */
2323                         if (!(attribute & 0x10))        /* exclude dirs */
2324                                 return CM_ERROR_NOFILES;
2325                         rootPath = 1;
2326                 }
2327
2328                 dsp = smb_NewDirSearch(0);
2329                 dsp->attribute = attribute;
2330                 smb_Get8Dot3MaskFromPath(mask, pathp);
2331                 memcpy(dsp->mask, mask, 11);
2332
2333                 /* track if this is likely to match a lot of entries */
2334                 if (smb_IsStarMask(mask)) starPattern = 1;
2335                 else starPattern = 0;
2336         }
2337         else {
2338                 /* pull the next cookie value out of the search status block */
2339                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
2340                         + (inCookiep[16]<<24);
2341                 dsp = smb_FindDirSearch(inCookiep[12]);
2342                 if (!dsp) {
2343                         /* can't find dir search status; fatal error */
2344                         return CM_ERROR_BADFD;
2345                 }
2346                 attribute = dsp->attribute;
2347                 resByte = inCookiep[0];
2348
2349                 /* copy out client cookie, in host byte order.  Don't bother
2350                  * interpreting it, since we're just passing it through, anyway.
2351                  */
2352                 memcpy(&clientCookie, &inCookiep[17], 4);
2353
2354                 memcpy(mask, dsp->mask, 11);
2355
2356                 /* assume we're doing a star match if it has continued for more
2357                  * than one call.
2358                  */
2359                 starPattern = 1;
2360         }
2361
2362         osi_Log3(afsd_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
2363                 nextCookie, dsp->cookie, attribute);
2364
2365         userp = smb_GetUser(vcp, inp);
2366
2367         /* try to get the vnode for the path name next */
2368         lock_ObtainMutex(&dsp->mx);
2369         if (dsp->scp) {
2370                 scp = dsp->scp;
2371                 cm_HoldSCache(scp);
2372                 code = 0;
2373         }
2374         else {
2375                 spacep = inp->spacep;
2376                 smb_StripLastComponent(spacep->data, NULL, pathp);
2377                 lock_ReleaseMutex(&dsp->mx);
2378                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2379                 code = cm_NameI(cm_rootSCachep, spacep->data,
2380                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
2381                 lock_ObtainMutex(&dsp->mx);
2382                 if (code == 0) {
2383                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
2384                         dsp->scp = scp;
2385                         /* we need one hold for the entry we just stored into,
2386                          * and one for our own processing.  When we're done with this
2387                          * function, we'll drop the one for our own processing.
2388                          * We held it once from the namei call, and so we do another hold
2389                          * now.
2390                          */
2391                         cm_HoldSCache(scp);
2392                         lock_ObtainMutex(&scp->mx);
2393                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
2394                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
2395                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
2396                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
2397                         }
2398                         lock_ReleaseMutex(&scp->mx);
2399                 }
2400         }
2401         lock_ReleaseMutex(&dsp->mx);
2402         if (code) {
2403                 cm_ReleaseUser(userp);
2404                 smb_DeleteDirSearch(dsp);
2405                 smb_ReleaseDirSearch(dsp);
2406                 return code;
2407         }
2408
2409         /* reserves space for parameter; we'll adjust it again later to the
2410          * real count of the # of entries we returned once we've actually
2411          * assembled the directory listing.
2412          */
2413         smb_SetSMBParm(outp, 0, 0);
2414         
2415         /* get the directory size */
2416         lock_ObtainMutex(&scp->mx);
2417         code = cm_SyncOp(scp, NULL, userp, &req, 0,
2418                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2419         if (code) {
2420                 lock_ReleaseMutex(&scp->mx);
2421                 cm_ReleaseSCache(scp);
2422                 cm_ReleaseUser(userp);
2423                 smb_DeleteDirSearch(dsp);
2424                 smb_ReleaseDirSearch(dsp);
2425                 return code;
2426         }
2427         
2428         dirLength = scp->length;
2429         bufferp = NULL;
2430         bufferOffset.LowPart = bufferOffset.HighPart = 0;
2431         curOffset.HighPart = 0;
2432         curOffset.LowPart = nextCookie;
2433         origOp = op = smb_GetSMBData(outp, NULL);
2434         /* and write out the basic header */
2435         *op++ = 5;              /* variable block */
2436         op += 2;                /* skip vbl block length; we'll fill it in later */
2437         code = 0;
2438         returnedNames = 0;
2439         while (1) {
2440                 /* make sure that curOffset.LowPart doesn't point to the first
2441                  * 32 bytes in the 2nd through last dir page, and that it doesn't
2442                  * point at the first 13 32-byte chunks in the first dir page,
2443                  * since those are dir and page headers, and don't contain useful
2444                  * information.
2445                  */
2446                 temp = curOffset.LowPart & (2048-1);
2447                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
2448                         /* we're in the first page */
2449                         if (temp < 13*32) temp = 13*32;
2450                 }
2451                 else {
2452                         /* we're in a later dir page */
2453                         if (temp < 32) temp = 32;
2454                 }
2455                 
2456                 /* make sure the low order 5 bits are zero */
2457                 temp &= ~(32-1);
2458                 
2459                 /* now put temp bits back ito curOffset.LowPart */
2460                 curOffset.LowPart &= ~(2048-1);
2461                 curOffset.LowPart |= temp;
2462
2463                 /* check if we've returned all the names that will fit in the
2464                  * response packet.
2465                  */
2466                 if (returnedNames >= maxCount) break;
2467                 
2468                 /* check if we've passed the dir's EOF */
2469                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
2470                 
2471                 /* see if we can use the bufferp we have now; compute in which page
2472                  * the current offset would be, and check whether that's the offset
2473                  * of the buffer we have.  If not, get the buffer.
2474                  */
2475                 thyper.HighPart = curOffset.HighPart;
2476                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
2477                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
2478                         /* wrong buffer */
2479                         if (bufferp) {
2480                                 buf_Release(bufferp);
2481                                 bufferp = NULL;
2482                         }
2483                         lock_ReleaseMutex(&scp->mx);
2484                         lock_ObtainRead(&scp->bufCreateLock);
2485                         code = buf_Get(scp, &thyper, &bufferp);
2486                         lock_ReleaseRead(&scp->bufCreateLock);
2487
2488                         /* now, if we're doing a star match, do bulk fetching of all of 
2489                          * the status info for files in the dir.
2490                          */
2491                         if (starPattern) {
2492                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
2493                                                         &req);
2494                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
2495                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
2496                                                                         scp->bulkStatProgress)) {
2497                                   /* Don't bulk stat if risking timeout */
2498                                   int now = GetCurrentTime();
2499                                   if (now - req.startTime > 5000) {
2500                                     scp->bulkStatProgress = thyper;
2501                                     scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
2502                                     dsp->flags &= ~SMB_DIRSEARCH_BULKST;
2503                                   } else
2504                                     cm_TryBulkStat(scp, &thyper,
2505                                                    userp, &req);
2506                                 }
2507                         }
2508
2509                         lock_ObtainMutex(&scp->mx);
2510                         if (code) break;
2511                         bufferOffset = thyper;
2512
2513                         /* now get the data in the cache */
2514                         while (1) {
2515                                 code = cm_SyncOp(scp, bufferp, userp, &req,
2516                                         PRSFS_LOOKUP,
2517                                         CM_SCACHESYNC_NEEDCALLBACK
2518                                         | CM_SCACHESYNC_READ);
2519                                 if (code) break;
2520                                 
2521                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
2522                                 
2523                                 /* otherwise, load the buffer and try again */
2524                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
2525                                                     &req);
2526                                 if (code) break;
2527                         }
2528                         if (code) {
2529                                 buf_Release(bufferp);
2530                                 bufferp = NULL;
2531                                 break;
2532                         }
2533                 }       /* if (wrong buffer) ... */
2534                 
2535                 /* now we have the buffer containing the entry we're interested in; copy
2536                  * it out if it represents a non-deleted entry.
2537                  */
2538                 entryInDir = curOffset.LowPart & (2048-1);
2539                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
2540
2541                 /* page header will help tell us which entries are free.  Page header
2542                  * can change more often than once per buffer, since AFS 3 dir page size
2543                  * may be less than (but not more than a buffer package buffer.
2544                  */
2545                 temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
2546                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
2547                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
2548
2549                 /* now determine which entry we're looking at in the page.  If it is
2550                  * free (there's a free bitmap at the start of the dir), we should
2551                  * skip these 32 bytes.
2552                  */
2553                 slotInPage = (entryInDir & 0x7e0) >> 5;
2554                 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
2555                         /* this entry is free */
2556                         numDirChunks = 1;               /* only skip this guy */
2557                         goto nextEntry;
2558                 }
2559
2560                 tp = bufferp->datap + entryInBuffer;
2561                 dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
2562
2563                 /* while we're here, compute the next entry's location, too,
2564                  * since we'll need it when writing out the cookie into the dir
2565                  * listing stream.
2566                  *
2567                  * XXXX Probably should do more sanity checking.
2568                  */
2569                 numDirChunks = cm_NameEntries(dep->name, NULL);
2570                 
2571                 /* compute the offset of the cookie representing the next entry */
2572                 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
2573
2574                 /* Compute 8.3 name if necessary */
2575                 actualName = dep->name;
2576                 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
2577                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
2578                         actualName = shortName;
2579                 }
2580
2581                 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
2582                         /* this is one of the entries to use: it is not deleted
2583                          * and it matches the star pattern we're looking for.
2584                          */
2585                         *op++ = resByte;
2586                         memcpy(op, mask, 11); op += 11;
2587                         *op++ = (char) dsp->cookie;     /* they say it must be non-zero */
2588                         *op++ = nextEntryCookie & 0xff;
2589                         *op++ = (nextEntryCookie>>8) & 0xff;
2590                         *op++ = (nextEntryCookie>>16) & 0xff;
2591                         *op++ = (nextEntryCookie>>24) & 0xff;
2592                         memcpy(op, &clientCookie, 4); op += 4;
2593                         
2594                         /* now we emit the attribute.  This is sort of tricky,
2595                          * since we need to really stat the file to find out
2596                          * what type of entry we've got.  Right now, we're
2597                          * copying out data from a buffer, while holding the
2598                          * scp locked, so it isn't really convenient to stat
2599                          * something now.  We'll put in a place holder now,
2600                          * and make a second pass before returning this to get
2601                          * the real attributes.  So, we just skip the data for
2602                          * now, and adjust it later.  We allocate a patch
2603                          * record to make it easy to find this point later.
2604                          * The replay will happen at a time when it is safe to
2605                          * unlock the directory.
2606                          */
2607                         curPatchp = malloc(sizeof(*curPatchp));
2608                         osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
2609                         curPatchp->dptr = op;
2610                         curPatchp->fid.cell = scp->fid.cell;
2611                         curPatchp->fid.volume = scp->fid.volume;
2612                         curPatchp->fid.vnode = ntohl(dep->fid.vnode);
2613                         curPatchp->fid.unique = ntohl(dep->fid.unique);
2614                         op += 9;        /* skip attr, time, date and size */
2615                         
2616                         /* zero out name area.  The spec says to pad with
2617                          * spaces, but Samba doesn't, and neither do we.
2618                          */
2619                         memset(op, 0, 13);
2620
2621                         /* finally, we get to copy out the name; we know that
2622                          * it fits in 8.3 or the pattern wouldn't match, but it
2623                          * never hurts to be sure.
2624                          */
2625                         strncpy(op, actualName, 13);
2626
2627                         /* Uppercase if requested by client */
2628                         if ((((smb_t *)inp)->flg2 & 1) == 0)
2629                                 _strupr(op);
2630
2631                         op += 13;
2632
2633                         /* now, adjust the # of entries copied */
2634                         returnedNames++;
2635                 }       /* if we're including this name */
2636                 
2637 nextEntry:
2638                 /* and adjust curOffset to be where the new cookie is */
2639                 thyper.HighPart = 0;
2640                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
2641                 curOffset = LargeIntegerAdd(thyper, curOffset);
2642         }               /* while copying data for dir listing */
2643
2644         /* release the mutex */
2645         lock_ReleaseMutex(&scp->mx);
2646         if (bufferp) buf_Release(bufferp);
2647
2648         /* apply and free last set of patches; if not doing a star match, this
2649          * will be empty, but better safe (and freeing everything) than sorry.
2650          */
2651         smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
2652
2653         /* special return code for unsuccessful search */
2654         if (code == 0 && dataLength < 21 && returnedNames == 0)
2655                 code = CM_ERROR_NOFILES;
2656
2657         osi_Log2(afsd_logp, "SMB search dir done, %d names, code %d",
2658                  returnedNames, code);
2659
2660         if (code != 0) {
2661                 smb_DeleteDirSearch(dsp);
2662                 smb_ReleaseDirSearch(dsp);
2663                 cm_ReleaseSCache(scp);
2664                 cm_ReleaseUser(userp);
2665                 return code;
2666         }
2667
2668         /* finalize the output buffer */
2669         smb_SetSMBParm(outp, 0, returnedNames);
2670         temp = (long) (op - origOp);
2671         smb_SetSMBDataLength(outp, temp);
2672
2673         /* the data area is a variable block, which has a 5 (already there)
2674          * followed by the length of the # of data bytes.  We now know this to
2675          * be "temp," although that includes the 3 bytes of vbl block header.
2676          * Deduct for them and fill in the length field.
2677          */
2678         temp -= 3;              /* deduct vbl block info */
2679         osi_assert(temp == (43 * returnedNames));
2680         origOp[1] = temp & 0xff;
2681         origOp[2] = (temp>>8) & 0xff;
2682         if (returnedNames == 0) smb_DeleteDirSearch(dsp);
2683         smb_ReleaseDirSearch(dsp);
2684         cm_ReleaseSCache(scp);
2685         cm_ReleaseUser(userp);
2686         return code;
2687 }
2688
2689 /* verify that this is a valid path to a directory.  I don't know why they
2690  * don't use the get file attributes call.
2691  */
2692 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2693 {
2694         char *pathp;
2695         long code;
2696         cm_scache_t *rootScp;
2697         cm_scache_t *newScp;
2698         cm_user_t *userp;
2699         unsigned int attrs;
2700         int caseFold;
2701         char *tidPathp;
2702         cm_req_t req;
2703
2704         cm_InitReq(&req);
2705
2706         pathp = smb_GetSMBData(inp, NULL);
2707         pathp = smb_ParseASCIIBlock(pathp, NULL);
2708         osi_Log1(afsd_logp, "SMB receive check path %s",
2709                         osi_LogSaveString(afsd_logp, pathp));
2710         
2711         if (!pathp) {
2712                 return CM_ERROR_BADFD;
2713         }
2714         
2715         rootScp = cm_rootSCachep;
2716         
2717         userp = smb_GetUser(vcp, inp);
2718
2719         caseFold = CM_FLAG_CASEFOLD;
2720
2721         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2722         code = cm_NameI(rootScp, pathp,
2723                         caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
2724                         userp, tidPathp, &req, &newScp);
2725
2726         if (code) {
2727                 cm_ReleaseUser(userp);
2728                 return code;
2729         }
2730         
2731         /* now lock the vnode with a callback; returns with newScp locked */
2732         lock_ObtainMutex(&newScp->mx);
2733         code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
2734                 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
2735         if (code && code != CM_ERROR_NOACCESS) {
2736                 lock_ReleaseMutex(&newScp->mx);
2737                 cm_ReleaseSCache(newScp);
2738                 cm_ReleaseUser(userp);
2739                 return code;
2740         }
2741
2742         attrs = smb_Attributes(newScp);
2743
2744         if (!(attrs & 0x10))
2745                 code = CM_ERROR_NOTDIR;
2746
2747         lock_ReleaseMutex(&newScp->mx);
2748         
2749         cm_ReleaseSCache(newScp);
2750         cm_ReleaseUser(userp);
2751         return code;
2752 }
2753
2754 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2755 {
2756         char *pathp;
2757         long code;
2758         cm_scache_t *rootScp;
2759         unsigned short attribute;
2760         cm_attr_t attr;
2761         cm_scache_t *newScp;
2762         long dosTime;
2763         cm_user_t *userp;
2764         int caseFold;
2765         char *tidPathp;
2766         cm_req_t req;
2767
2768         cm_InitReq(&req);
2769
2770         /* decode basic attributes we're passed */
2771         attribute = smb_GetSMBParm(inp, 0);
2772         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2773
2774         pathp = smb_GetSMBData(inp, NULL);
2775         pathp = smb_ParseASCIIBlock(pathp, NULL);
2776         
2777         if (!pathp) {
2778                 return CM_ERROR_BADSMB;
2779         }
2780         
2781         osi_Log2(afsd_logp, "SMB receive setfile attributes time %d, attr 0x%x",
2782                 dosTime, attribute);
2783
2784         rootScp = cm_rootSCachep;
2785         
2786         userp = smb_GetUser(vcp, inp);
2787
2788         caseFold = CM_FLAG_CASEFOLD;
2789
2790         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2791         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
2792                         tidPathp, &req, &newScp);
2793
2794         if (code) {
2795                 cm_ReleaseUser(userp);
2796                 return code;
2797         }
2798         
2799         /* now lock the vnode with a callback; returns with newScp locked; we
2800          * need the current status to determine what the new status is, in some
2801          * cases.
2802          */
2803         lock_ObtainMutex(&newScp->mx);
2804         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
2805                 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
2806         if (code) {
2807                 lock_ReleaseMutex(&newScp->mx);
2808                 cm_ReleaseSCache(newScp);
2809                 cm_ReleaseUser(userp);
2810                 return code;
2811         }
2812
2813         /* Check for RO volume */
2814         if (newScp->flags & CM_SCACHEFLAG_RO) {
2815                 lock_ReleaseMutex(&newScp->mx);
2816                 cm_ReleaseSCache(newScp);
2817                 cm_ReleaseUser(userp);
2818                 return CM_ERROR_READONLY;
2819         }
2820
2821         /* prepare for setattr call */
2822         attr.mask = 0;
2823         if (dosTime != 0) {
2824                 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
2825                 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
2826         }
2827         if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
2828                 /* we're told to make a writable file read-only */
2829                 attr.unixModeBits = newScp->unixModeBits & ~0222;
2830                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2831         }
2832         else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
2833                 /* we're told to make a read-only file writable */
2834                 attr.unixModeBits = newScp->unixModeBits | 0222;
2835                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
2836         }
2837         lock_ReleaseMutex(&newScp->mx);
2838
2839         /* now call setattr */
2840         if (attr.mask)
2841                 code = cm_SetAttr(newScp, &attr, userp, &req);
2842         else
2843                 code = 0;
2844         
2845         cm_ReleaseSCache(newScp);
2846         cm_ReleaseUser(userp);
2847
2848         return code;
2849 }
2850
2851 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2852 {
2853         char *pathp;
2854         long code;
2855         cm_scache_t *rootScp;
2856         cm_scache_t *newScp, *dscp;
2857         long dosTime;
2858         int attrs;
2859         cm_user_t *userp;
2860         int caseFold;
2861         char *tidPathp;
2862         cm_space_t *spacep;
2863         char *lastComp;
2864         cm_req_t req;
2865
2866         cm_InitReq(&req);
2867
2868         pathp = smb_GetSMBData(inp, NULL);
2869         pathp = smb_ParseASCIIBlock(pathp, NULL);
2870         
2871         if (!pathp) {
2872                 return CM_ERROR_BADSMB;
2873         }
2874         
2875         if (*pathp == 0)                /* null path */
2876                 pathp = "\\";
2877
2878         osi_Log1(afsd_logp, "SMB receive getfile attributes path %s",
2879                         osi_LogSaveString(afsd_logp, pathp));
2880
2881         rootScp = cm_rootSCachep;
2882         
2883         userp = smb_GetUser(vcp, inp);
2884
2885         /* we shouldn't need this for V3 requests, but we seem to */
2886         caseFold = CM_FLAG_CASEFOLD;
2887
2888         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
2889
2890         /*
2891          * XXX Strange hack XXX
2892          *
2893          * As of Patch 5 (16 July 97), we are having the following problem:
2894          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
2895          * requests to look up "desktop.ini" in all the subdirectories.
2896          * This can cause zillions of timeouts looking up non-existent cells
2897          * and volumes, especially in the top-level directory.
2898          *
2899          * We have not found any way to avoid this or work around it except
2900          * to explicitly ignore the requests for mount points that haven't
2901          * yet been evaluated and for directories that haven't yet been
2902          * fetched.
2903          */
2904         spacep = inp->spacep;
2905         smb_StripLastComponent(spacep->data, &lastComp, pathp);
2906         if (strcmp(lastComp, "\\desktop.ini") == 0) {
2907                 code = cm_NameI(rootScp, spacep->data,
2908                         caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
2909                         userp, tidPathp, &req, &dscp);
2910                 if (code == 0) {
2911                         if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
2912                             && !dscp->mountRootFidp)
2913                                 code = CM_ERROR_NOSUCHFILE;
2914                         else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
2915                                 cm_buf_t *bp = buf_Find(dscp, &hzero);
2916                                 if (bp)
2917                                         buf_Release(bp);
2918                                 else
2919                                         code = CM_ERROR_NOSUCHFILE;
2920                         }
2921                         cm_ReleaseSCache(dscp);
2922                         if (code) {
2923                                 cm_ReleaseUser(userp);
2924                                 return code;
2925                         }
2926                 }
2927         }
2928
2929         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
2930                         tidPathp, &req, &newScp);
2931
2932         if (code) {
2933                 cm_ReleaseUser(userp);
2934                 return code;
2935         }
2936         
2937         /* now lock the vnode with a callback; returns with newScp locked */
2938         lock_ObtainMutex(&newScp->mx);
2939         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
2940                 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
2941         if (code) {
2942                 lock_ReleaseMutex(&newScp->mx);
2943                 cm_ReleaseSCache(newScp);
2944                 cm_ReleaseUser(userp);
2945                 return code;
2946         }
2947
2948         if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
2949                 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
2950                         attrs = 0x10;
2951         else
2952                 attrs = 0;
2953         if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
2954                 attrs |= 1;     /* turn on read-only flag */
2955         smb_SetSMBParm(outp, 0, attrs);
2956         
2957         smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
2958         smb_SetSMBParm(outp, 1, dosTime & 0xffff);
2959         smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
2960         smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
2961         smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
2962         smb_SetSMBParm(outp, 5, 0);
2963         smb_SetSMBParm(outp, 6, 0);
2964         smb_SetSMBParm(outp, 7, 0);
2965         smb_SetSMBParm(outp, 8, 0);
2966         smb_SetSMBParm(outp, 9, 0);
2967         smb_SetSMBDataLength(outp, 0);
2968         lock_ReleaseMutex(&newScp->mx);
2969         
2970         cm_ReleaseSCache(newScp);
2971         cm_ReleaseUser(userp);
2972         
2973         return 0;
2974 }
2975
2976 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2977 {
2978         smb_tid_t *tidp;
2979         
2980         osi_Log0(afsd_logp, "SMB receive tree disconnect");
2981
2982         /* find the tree and free it */
2983         tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
2984         if (tidp) {
2985                 lock_ObtainMutex(&tidp->mx);
2986                 tidp->flags |= SMB_TIDFLAG_DELETE;
2987                 lock_ReleaseMutex(&tidp->mx);
2988                 smb_ReleaseTID(tidp);
2989         }
2990
2991         return 0;
2992 }
2993
2994 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2995 {
2996         smb_fid_t *fidp;
2997         char *pathp;
2998         char *lastNamep;
2999         int share;
3000         int attribute;
3001         long code;
3002         cm_user_t *userp;
3003         cm_scache_t *scp;
3004         long dosTime;
3005         int caseFold;
3006         cm_space_t *spacep;
3007         char *tidPathp;
3008         cm_req_t req;
3009
3010         cm_InitReq(&req);
3011
3012         osi_Log0(afsd_logp, "SMB receive open");
3013
3014         pathp = smb_GetSMBData(inp, NULL);
3015         pathp = smb_ParseASCIIBlock(pathp, NULL);
3016         
3017         share = smb_GetSMBParm(inp, 0);
3018         attribute = smb_GetSMBParm(inp, 1);
3019
3020         spacep = inp->spacep;
3021         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3022         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3023                 /* special case magic file name for receiving IOCTL requests
3024                  * (since IOCTL calls themselves aren't getting through).
3025                  */
3026                 fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3027                 smb_SetupIoctlFid(fidp, spacep);
3028                 smb_SetSMBParm(outp, 0, fidp->fid);
3029                 smb_SetSMBParm(outp, 1, 0);     /* attrs */
3030                 smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
3031                 smb_SetSMBParm(outp, 3, 0);
3032                 smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
3033                 smb_SetSMBParm(outp, 5, 0x7fff);
3034                 /* pass the open mode back */
3035                 smb_SetSMBParm(outp, 6, (share & 0xf));
3036                 smb_SetSMBDataLength(outp, 0);
3037                 smb_ReleaseFID(fidp);
3038                 return 0;
3039         }
3040
3041         userp = smb_GetUser(vcp, inp);
3042
3043         caseFold = CM_FLAG_CASEFOLD;
3044
3045         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3046         code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3047                         tidPathp, &req, &scp);
3048         
3049         if (code) {
3050                 cm_ReleaseUser(userp);
3051                 return code;
3052         }
3053         
3054         code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3055         if (code) {
3056                 cm_ReleaseSCache(scp);
3057                 cm_ReleaseUser(userp);
3058                 return code;
3059         }
3060
3061         /* don't need callback to check file type, since file types never
3062          * change, and namei and cm_Lookup all stat the object at least once on
3063          * a successful return.
3064          */
3065         if (scp->fileType != CM_SCACHETYPE_FILE) {
3066                 cm_ReleaseSCache(scp);
3067                 cm_ReleaseUser(userp);
3068                 return CM_ERROR_ISDIR;
3069         }
3070
3071         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3072         osi_assert(fidp);
3073
3074         /* save a pointer to the vnode */
3075         fidp->scp = scp;
3076         
3077         if ((share & 0xf) == 0)
3078                 fidp->flags |= SMB_FID_OPENREAD;
3079         else if ((share & 0xf) == 1)
3080                 fidp->flags |= SMB_FID_OPENWRITE;
3081         else fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3082
3083         lock_ObtainMutex(&scp->mx);
3084         smb_SetSMBParm(outp, 0, fidp->fid);
3085         smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3086         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3087         smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3088         smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3089         smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3090         smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3091         /* pass the open mode back; XXXX add access checks */
3092         smb_SetSMBParm(outp, 6, (share & 0xf));
3093         smb_SetSMBDataLength(outp, 0);
3094         lock_ReleaseMutex(&scp->mx);
3095         
3096         /* notify open */
3097         cm_Open(scp, 0, userp);
3098
3099         /* send and free packet */
3100         smb_ReleaseFID(fidp);
3101         cm_ReleaseUser(userp);
3102         /* don't release scp, since we've squirreled away the pointer in the fid struct */
3103
3104         return 0;
3105 }
3106
3107 typedef struct smb_unlinkRock {
3108         cm_scache_t *dscp;
3109         cm_user_t *userp;
3110         cm_req_t *reqp;
3111         smb_vc_t *vcp;
3112         char *maskp;            /* pointer to the star pattern */
3113         int hasTilde;
3114         int any;
3115 } smb_unlinkRock_t;
3116
3117 long smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3118 {
3119         long code;
3120         smb_unlinkRock_t *rockp;
3121         int caseFold;
3122         int match;
3123         char shortName[13];
3124         char *matchName;
3125         
3126         rockp = vrockp;
3127
3128         if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3129                 caseFold = CM_FLAG_CASEFOLD;
3130         else 
3131                 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3132
3133         matchName = dep->name;
3134         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3135         if (!match
3136             && rockp->hasTilde
3137             && !cm_Is8Dot3(dep->name)) {
3138                 cm_Gen8Dot3Name(dep, shortName, NULL);
3139                 matchName = shortName;
3140                 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3141         }
3142         if (match) {
3143                 osi_Log1(smb_logp, "Unlinking %s",
3144                                 osi_LogSaveString(smb_logp, matchName));
3145                 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3146                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3147                         smb_NotifyChange(FILE_ACTION_REMOVED,
3148                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3149                                          dscp, dep->name, NULL, TRUE);
3150                 if (code == 0)
3151                         rockp->any = 1;
3152         }
3153         else code = 0;
3154
3155         return code;
3156 }
3157
3158 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3159 {
3160         int attribute;
3161         long code;
3162         char *pathp;
3163         char *tp;
3164         cm_space_t *spacep;
3165         cm_scache_t *dscp;
3166         char *lastNamep;
3167         smb_unlinkRock_t rock;
3168         cm_user_t *userp;
3169         osi_hyper_t thyper;
3170         int caseFold;
3171         char *tidPathp;
3172         cm_req_t req;
3173
3174         cm_InitReq(&req);
3175
3176         attribute = smb_GetSMBParm(inp, 0);
3177         
3178         tp = smb_GetSMBData(inp, NULL);
3179         pathp = smb_ParseASCIIBlock(tp, &tp);
3180
3181         osi_Log1(smb_logp, "SMB receive unlink %s",
3182                         osi_LogSaveString(smb_logp, pathp));
3183
3184         spacep = inp->spacep;
3185         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3186
3187         userp = smb_GetUser(vcp, inp);
3188
3189         caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3190
3191         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3192         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
3193                         &req, &dscp);
3194
3195         if (code) {
3196                 cm_ReleaseUser(userp);
3197                 return code;
3198         }
3199         
3200         /* otherwise, scp points to the parent directory.
3201          */
3202         if (!lastNamep) lastNamep = pathp;
3203         else lastNamep++;
3204
3205         rock.any = 0;
3206         rock.maskp = smb_FindMask(pathp);
3207         rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
3208         
3209         thyper.LowPart = 0;
3210         thyper.HighPart = 0;
3211         rock.userp = userp;
3212         rock.reqp = &req;
3213         rock.dscp = dscp;
3214         rock.vcp = vcp;
3215         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
3216
3217         cm_ReleaseUser(userp);
3218         
3219         cm_ReleaseSCache(dscp);
3220
3221         if (code == 0 && !rock.any)
3222                 code = CM_ERROR_NOSUCHFILE;
3223         return code;
3224 }
3225
3226 typedef struct smb_renameRock {
3227         cm_scache_t *odscp;     /* old dir */
3228         cm_scache_t *ndscp;     /* new dir */
3229         cm_user_t *userp;       /* user */
3230         cm_req_t *reqp;         /* request struct */
3231         smb_vc_t *vcp;          /* virtual circuit */
3232         char *maskp;            /* pointer to star pattern of old file name */
3233         int hasTilde;           /* star pattern might be shortname? */
3234         char *newNamep;         /* ptr to the new file's name */
3235 } smb_renameRock_t;
3236
3237 long smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3238 {
3239         long code;
3240         smb_renameRock_t *rockp;
3241         int caseFold;
3242         int match;
3243         char shortName[13];
3244         
3245         rockp = vrockp;
3246
3247         if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3248                 caseFold = CM_FLAG_CASEFOLD;
3249         else 
3250                 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3251
3252         match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
3253         if (!match
3254             && rockp->hasTilde
3255             && !cm_Is8Dot3(dep->name)) {
3256                 cm_Gen8Dot3Name(dep, shortName, NULL);
3257                 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
3258         }
3259         if (match) {
3260                 code = cm_Rename(rockp->odscp, dep->name,
3261                         rockp->ndscp, rockp->newNamep, rockp->userp,
3262                         rockp->reqp);
3263                 /* if the call worked, stop doing the search now, since we
3264                  * really only want to rename one file.
3265                  */
3266                 if (code == 0) code = CM_ERROR_STOPNOW;
3267         }
3268         else code = 0;
3269
3270         return code;
3271 }
3272
3273 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3274 {
3275         long code;
3276         char *oldPathp;
3277         char *newPathp;
3278         char *tp;
3279         cm_space_t *spacep;
3280         smb_renameRock_t rock;
3281         cm_scache_t *oldDscp;
3282         cm_scache_t *newDscp;
3283         char *oldLastNamep;
3284         char *newLastNamep;
3285         osi_hyper_t thyper;
3286         cm_user_t *userp;
3287         int caseFold;
3288         char *tidPathp;
3289         DWORD filter;
3290         cm_req_t req;
3291
3292         cm_InitReq(&req);
3293         
3294         tp = smb_GetSMBData(inp, NULL);
3295         oldPathp = smb_ParseASCIIBlock(tp, &tp);
3296         newPathp = smb_ParseASCIIBlock(tp, &tp);
3297
3298         osi_Log2(afsd_logp, "smb rename %s to %s",
3299                  osi_LogSaveString(afsd_logp, oldPathp),
3300                  osi_LogSaveString(afsd_logp, newPathp));
3301
3302         spacep = inp->spacep;
3303         smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
3304
3305         userp = smb_GetUser(vcp, inp);
3306
3307 /*
3308  * Changed to use CASEFOLD always.  This enables us to rename Foo/baz when
3309  * what actually exists is foo/baz.  I don't know why the code used to be
3310  * the way it was.  1/29/96
3311  *
3312  *      caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
3313  *
3314  * Changed to use CM_FLAG_FOLLOW.  7/24/96
3315  *
3316  *      caseFold = CM_FLAG_CASEFOLD;
3317  */
3318         caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3319
3320         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3321         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
3322                 userp, tidPathp, &req, &oldDscp);
3323
3324         if (code) {
3325                 cm_ReleaseUser(userp);
3326                 return code;
3327         }
3328         
3329         smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
3330         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
3331                 userp, tidPathp, &req, &newDscp);
3332
3333         if (code) {
3334                 cm_ReleaseSCache(oldDscp);
3335                 cm_ReleaseUser(userp);
3336                 return code;
3337         }
3338         
3339         /* otherwise, oldDscp and newDscp point to the corresponding directories.
3340          * next, get the component names, and lower case them.
3341          */
3342
3343         /* handle the old name first */
3344         if (!oldLastNamep) oldLastNamep = oldPathp;
3345         else oldLastNamep++;
3346
3347         /* and handle the new name, too */
3348         if (!newLastNamep) newLastNamep = newPathp;
3349         else newLastNamep++;
3350         
3351         /* do the vnode call */
3352         rock.odscp = oldDscp;
3353         rock.ndscp = newDscp;
3354         rock.userp = userp;
3355         rock.reqp = &req;
3356         rock.vcp = vcp;
3357         rock.maskp = oldLastNamep;
3358         rock.hasTilde = ((strchr(oldLastNamep, '~') != NULL) ? 1 : 0);
3359         rock.newNamep = newLastNamep;
3360
3361         /* now search the dir for the pattern, and do the appropriate rename when
3362          * found.
3363          */
3364         thyper.LowPart = 0;             /* search dir from here */
3365         thyper.HighPart = 0;
3366         code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
3367
3368         if (code == CM_ERROR_STOPNOW)
3369                 code = 0;
3370         else if (code == 0)
3371                 code = CM_ERROR_NOSUCHFILE;
3372
3373         /* Handle Change Notification */
3374         /*
3375          * Being lazy, not distinguishing between files and dirs in this
3376          * filter, since we'd have to do a lookup.
3377          */
3378         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
3379         if (oldDscp == newDscp) {
3380                 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
3381                         smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
3382                                          filter, oldDscp, oldLastNamep,
3383                                          newLastNamep, TRUE);
3384         } else {
3385                 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
3386                         smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
3387                                          filter, oldDscp, oldLastNamep,
3388                                          NULL, TRUE);
3389                 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
3390                         smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
3391                                          filter, newDscp, newLastNamep,
3392                                          NULL, TRUE);
3393         }
3394
3395         cm_ReleaseUser(userp);
3396         
3397         cm_ReleaseSCache(oldDscp);
3398         cm_ReleaseSCache(newDscp);
3399         
3400         return code;
3401 }
3402
3403 typedef struct smb_rmdirRock {
3404         cm_scache_t *dscp;
3405         cm_user_t *userp;
3406         cm_req_t *reqp;
3407         char *maskp;            /* pointer to the star pattern */
3408         int hasTilde;
3409         int any;
3410 } smb_rmdirRock_t;
3411
3412 long smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3413 {
3414         long code;
3415         smb_rmdirRock_t *rockp;
3416         int match;
3417         char shortName[13];
3418         char *matchName;
3419         
3420         rockp = vrockp;
3421
3422         matchName = dep->name;
3423         match = (cm_stricmp(matchName, rockp->maskp) == 0);
3424         if (!match
3425             && rockp->hasTilde
3426             && !cm_Is8Dot3(dep->name)) {
3427                 cm_Gen8Dot3Name(dep, shortName, NULL);
3428                 matchName = shortName;
3429                 match = (cm_stricmp(matchName, rockp->maskp) == 0);
3430         }
3431         if (match) {
3432                 osi_Log1(smb_logp, "Removing directory %s",
3433                                 osi_LogSaveString(smb_logp, matchName));
3434                 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
3435                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3436                         smb_NotifyChange(FILE_ACTION_REMOVED,
3437                                          FILE_NOTIFY_CHANGE_DIR_NAME,
3438                                          dscp, dep->name, NULL, TRUE);
3439                 if (code == 0)
3440                         rockp->any = 1;
3441         }
3442         else code = 0;
3443
3444         return code;
3445 }
3446
3447 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3448 {
3449         long code;
3450         char *pathp;
3451         char *tp;
3452         cm_space_t *spacep;
3453         cm_scache_t *dscp;
3454         char *lastNamep;
3455         smb_rmdirRock_t rock;
3456         cm_user_t *userp;
3457         osi_hyper_t thyper;
3458         int caseFold;
3459         char *tidPathp;
3460         cm_req_t req;
3461
3462         cm_InitReq(&req);
3463
3464         tp = smb_GetSMBData(inp, NULL);
3465         pathp = smb_ParseASCIIBlock(tp, &tp);
3466
3467         spacep = inp->spacep;
3468         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3469
3470         userp = smb_GetUser(vcp, inp);
3471
3472         caseFold = CM_FLAG_CASEFOLD;
3473
3474         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3475         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
3476                 userp, tidPathp, &req, &dscp);
3477
3478         if (code) {
3479                 cm_ReleaseUser(userp);
3480                 return code;
3481         }
3482         
3483         /* otherwise, scp points to the parent directory. */
3484         if (!lastNamep) lastNamep = pathp;
3485         else lastNamep++;
3486         
3487         rock.any = 0;
3488         rock.maskp = lastNamep;
3489         rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
3490
3491         thyper.LowPart = 0;
3492         thyper.HighPart = 0;
3493         rock.userp = userp;
3494         rock.reqp = &req;
3495         rock.dscp = dscp;
3496         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
3497
3498         cm_ReleaseUser(userp);
3499         
3500         cm_ReleaseSCache(dscp);
3501
3502         if (code == 0 && !rock.any)
3503                 code = CM_ERROR_NOSUCHFILE;        
3504         return code;
3505 }
3506
3507 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3508 {
3509         unsigned short fid;
3510         smb_fid_t *fidp;
3511         cm_user_t *userp;
3512         long code;
3513         cm_req_t req;
3514
3515         cm_InitReq(&req);
3516
3517         fid = smb_GetSMBParm(inp, 0);
3518         
3519         osi_Log1(afsd_logp, "SMB flush fid %d", fid);
3520
3521         fid = smb_ChainFID(fid, inp);
3522         fidp = smb_FindFID(vcp, fid, 0);
3523         if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
3524                 return CM_ERROR_BADFD;
3525         }
3526         
3527         userp = smb_GetUser(vcp, inp);
3528
3529         lock_ObtainMutex(&fidp->mx);
3530         if (fidp->flags & SMB_FID_OPENWRITE)
3531                 code = cm_FSync(fidp->scp, userp, &req);
3532         else code = 0;
3533         lock_ReleaseMutex(&fidp->mx);
3534         
3535         smb_ReleaseFID(fidp);
3536         
3537         cm_ReleaseUser(userp);
3538         
3539         return code;
3540 }
3541
3542 struct smb_FullNameRock {
3543         char *name;
3544         cm_scache_t *vnode;
3545         char *fullName;
3546 };
3547
3548 long smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
3549         osi_hyper_t *offp)
3550 {
3551         char shortName[13];
3552         struct smb_FullNameRock *vrockp;
3553
3554         vrockp = rockp;
3555
3556         if (!cm_Is8Dot3(dep->name)) {
3557                 cm_Gen8Dot3Name(dep, shortName, NULL);
3558
3559                 if (strcmp(shortName, vrockp->name) == 0) {
3560                         vrockp->fullName = strdup(dep->name);
3561                         return CM_ERROR_STOPNOW;
3562                 }
3563         }
3564         if (stricmp(dep->name, vrockp->name) == 0
3565             && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
3566             && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
3567                 vrockp->fullName = strdup(dep->name);
3568                 return CM_ERROR_STOPNOW;
3569         }
3570         return 0;
3571 }
3572
3573 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
3574         char **newPathp, cm_user_t *userp, cm_req_t *reqp)
3575 {
3576         struct smb_FullNameRock rock;
3577         long code;
3578
3579         rock.name = pathp;
3580         rock.vnode = scp;
3581
3582         code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, 
3583                                 userp, reqp, NULL); 
3584         if (code == CM_ERROR_STOPNOW)
3585                 *newPathp = rock.fullName;
3586         else
3587                 *newPathp = strdup(pathp);
3588 }
3589
3590 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3591 {
3592         unsigned short fid;
3593         smb_fid_t *fidp;
3594         cm_user_t *userp;
3595         long dosTime;
3596         long code;
3597         cm_req_t req;
3598
3599         cm_InitReq(&req);
3600
3601         fid = smb_GetSMBParm(inp, 0);
3602         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3603         
3604         osi_Log1(afsd_logp, "SMB close fid %d", fid);
3605
3606         fid = smb_ChainFID(fid, inp);
3607         fidp = smb_FindFID(vcp, fid, 0);
3608         if (!fidp) {
3609                 return CM_ERROR_BADFD;
3610         }
3611         
3612         userp = smb_GetUser(vcp, inp);
3613
3614         lock_ObtainMutex(&fidp->mx);
3615
3616         /* Don't jump the gun on an async raw write */
3617         while (fidp->raw_writers) {
3618                 lock_ReleaseMutex(&fidp->mx);
3619                 WaitForSingleObject(fidp->raw_write_event, RAWTIMEOUT);
3620                 lock_ObtainMutex(&fidp->mx);
3621         }
3622
3623         fidp->flags |= SMB_FID_DELETE;
3624         
3625         /* watch for ioctl closes, and read-only opens */
3626         if (fidp->scp != NULL
3627             && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
3628                   == SMB_FID_OPENWRITE) {
3629                 if (dosTime != 0 && dosTime != -1) {
3630                         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
3631                         /* This fixes defect 10958 */
3632                         CompensateForSmbClientLastWriteTimeBugs(&dosTime);
3633                         smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime,
3634                                                  dosTime);
3635                 }
3636                 code = cm_FSync(fidp->scp, userp, &req);
3637         }
3638         else code = 0;
3639
3640         if (fidp->flags & SMB_FID_DELONCLOSE) {
3641                 cm_scache_t *dscp = fidp->NTopen_dscp;
3642                 char *pathp = fidp->NTopen_pathp;
3643                 char *fullPathp;
3644
3645                 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
3646                 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
3647                         code = cm_RemoveDir(dscp, fullPathp, userp, &req);
3648                         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3649                                 smb_NotifyChange(FILE_ACTION_REMOVED,
3650                                                  FILE_NOTIFY_CHANGE_DIR_NAME,
3651                                                  dscp, fullPathp, NULL, TRUE);
3652                 }
3653                 else {
3654                         code = cm_Unlink(dscp, fullPathp, userp, &req);
3655                         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3656                                 smb_NotifyChange(FILE_ACTION_REMOVED,
3657                                                  FILE_NOTIFY_CHANGE_FILE_NAME,
3658                                                  dscp, fullPathp, NULL, TRUE);
3659                 }
3660                 free(fullPathp);
3661         }
3662         lock_ReleaseMutex(&fidp->mx);
3663
3664         if (fidp->flags & SMB_FID_NTOPEN) {
3665                 cm_ReleaseSCache(fidp->NTopen_dscp);
3666                 free(fidp->NTopen_pathp);
3667         }
3668         if (fidp->NTopen_wholepathp)
3669                 free(fidp->NTopen_wholepathp);
3670         smb_ReleaseFID(fidp);
3671         
3672         cm_ReleaseUser(userp);
3673         
3674         return code;
3675 }
3676
3677 /*
3678  * smb_ReadData -- common code for Read, Read And X, and Raw Read
3679  */
3680 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
3681         cm_user_t *userp, long *readp)
3682 {
3683         osi_hyper_t offset;
3684         long code;
3685         cm_scache_t *scp;
3686         cm_buf_t *bufferp;
3687         osi_hyper_t fileLength;
3688         osi_hyper_t thyper;
3689         osi_hyper_t lastByte;
3690         osi_hyper_t bufferOffset;
3691         long bufIndex, nbytes;
3692         int chunk;
3693         int sequential = 0;
3694         cm_req_t req;
3695
3696         cm_InitReq(&req);
3697
3698         bufferp = NULL;
3699         offset = *offsetp;
3700
3701         lock_ObtainMutex(&fidp->mx);
3702         scp = fidp->scp;
3703         lock_ObtainMutex(&scp->mx);
3704
3705         if (offset.HighPart == 0) {
3706                 chunk = offset.LowPart >> cm_logChunkSize;
3707                 if (chunk != fidp->curr_chunk) {
3708                         fidp->prev_chunk = fidp->curr_chunk;
3709                         fidp->curr_chunk = chunk;
3710                 }
3711                 if (fidp->curr_chunk == fidp->prev_chunk + 1)
3712                         sequential = 1;
3713         }
3714
3715         /* start by looking up the file's end */
3716         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3717                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3718         if (code) goto done;
3719
3720         /* now we have the entry locked, look up the length */
3721         fileLength = scp->length;
3722
3723         /* adjust count down so that it won't go past EOF */
3724         thyper.LowPart = count;
3725         thyper.HighPart = 0;
3726         thyper = LargeIntegerAdd(offset, thyper);       /* where read should end */
3727         lastByte = thyper;
3728         if (LargeIntegerGreaterThan(thyper, fileLength)) {
3729                 /* we'd read past EOF, so just stop at fileLength bytes.
3730                  * Start by computing how many bytes remain in the file.
3731                  */
3732                 thyper = LargeIntegerSubtract(fileLength, offset);
3733
3734                 /* if we are past EOF, read 0 bytes */
3735                 if (LargeIntegerLessThanZero(thyper))
3736                         count = 0;
3737                 else
3738                         count = thyper.LowPart;
3739         }
3740
3741         *readp = count;
3742
3743         /* now, copy the data one buffer at a time,
3744          * until we've filled the request packet
3745          */
3746         while (1) {
3747                 /* if we've copied all the data requested, we're done */
3748                 if (count <= 0) break;
3749                 
3750                 /* otherwise, load up a buffer of data */
3751                 thyper.HighPart = offset.HighPart;
3752                 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
3753                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3754                         /* wrong buffer */
3755                         if (bufferp) {
3756                                 buf_Release(bufferp);
3757                                 bufferp = NULL;
3758                         }
3759                         lock_ReleaseMutex(&scp->mx);
3760
3761                         lock_ObtainRead(&scp->bufCreateLock);
3762                         code = buf_Get(scp, &thyper, &bufferp);
3763                         lock_ReleaseRead(&scp->bufCreateLock);
3764
3765                         lock_ObtainMutex(&scp->mx);
3766                         if (code) goto done;
3767                         bufferOffset = thyper;
3768
3769                         /* now get the data in the cache */
3770                         while (1) {
3771                                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
3772                                         CM_SCACHESYNC_NEEDCALLBACK
3773                                         | CM_SCACHESYNC_READ);
3774                                 if (code) goto done;
3775                                 
3776                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3777                                 
3778                                 /* otherwise, load the buffer and try again */
3779                                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
3780                                 if (code) break;
3781                         }
3782                         if (code) {
3783                                 buf_Release(bufferp);
3784                                 bufferp = NULL;
3785                                 goto done;
3786                         }
3787                 }       /* if (wrong buffer) ... */
3788                 
3789                 /* now we have the right buffer loaded.  Copy out the
3790                  * data from here to the user's buffer.
3791                  */
3792                 bufIndex = offset.LowPart & (buf_bufferSize - 1);
3793
3794                 /* and figure out how many bytes we want from this buffer */
3795                 nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
3796                 if (nbytes > count) nbytes = count;     /* don't go past EOF */
3797                 
3798                 /* now copy the data */
3799                 memcpy(op, bufferp->datap + bufIndex, nbytes);
3800                 
3801                 /* adjust counters, pointers, etc. */
3802                 op += nbytes;
3803                 count -= nbytes;
3804                 thyper.LowPart = nbytes;
3805                 thyper.HighPart = 0;
3806                 offset = LargeIntegerAdd(thyper, offset);
3807         } /* while 1 */
3808
3809 done:
3810         lock_ReleaseMutex(&scp->mx);
3811         lock_ReleaseMutex(&fidp->mx);
3812         if (bufferp) buf_Release(bufferp);
3813
3814         if (code == 0 && sequential)
3815                 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
3816
3817         return code;
3818 }
3819
3820 /*
3821  * smb_WriteData -- common code for Write and Raw Write
3822  */
3823 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
3824         cm_user_t *userp, long *writtenp)
3825 {
3826         osi_hyper_t offset;
3827         long code;
3828         long written = 0;
3829         cm_scache_t *scp;
3830         osi_hyper_t fileLength; /* file's length at start of write */
3831         osi_hyper_t minLength;  /* don't read past this */
3832         long nbytes;            /* # of bytes to transfer this iteration */
3833         cm_buf_t *bufferp;
3834         osi_hyper_t thyper;             /* hyper tmp variable */
3835         osi_hyper_t bufferOffset;
3836         long bufIndex;                  /* index in buffer where our data is */
3837         int doWriteBack;
3838         osi_hyper_t writeBackOffset;    /* offset of region to write back when
3839                                          * I/O is done */
3840         DWORD filter = 0;
3841         cm_req_t req;
3842
3843         cm_InitReq(&req);
3844
3845         bufferp = NULL;
3846         doWriteBack = 0;
3847         offset = *offsetp;
3848
3849         lock_ObtainMutex(&fidp->mx);
3850         scp = fidp->scp;
3851         lock_ObtainMutex(&scp->mx);
3852
3853         /* start by looking up the file's end */
3854         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3855                 CM_SCACHESYNC_NEEDCALLBACK
3856                  | CM_SCACHESYNC_SETSTATUS
3857                  | CM_SCACHESYNC_GETSTATUS);
3858         if (code) goto done;
3859         
3860         /* make sure we have a writable FD */
3861         if (!(fidp->flags & SMB_FID_OPENWRITE)) {
3862                 code = CM_ERROR_BADFDOP;
3863                 goto done;
3864         }
3865         
3866         /* now we have the entry locked, look up the length */
3867         fileLength = scp->length;
3868         minLength = fileLength;
3869         if (LargeIntegerGreaterThan(minLength, scp->serverLength))
3870                 minLength = scp->serverLength;
3871
3872         /* adjust file length if we extend past EOF */
3873         thyper.LowPart = count;
3874         thyper.HighPart = 0;
3875         thyper = LargeIntegerAdd(offset, thyper);       /* where write should end */
3876         if (LargeIntegerGreaterThan(thyper, fileLength)) {
3877                 /* we'd write past EOF, so extend the file */
3878                 scp->mask |= CM_SCACHEMASK_LENGTH;
3879                 scp->length = thyper;
3880                 filter |=
3881                     (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
3882         } else
3883                 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
3884         
3885         /* now, if the new position (thyper) and the old (offset) are in
3886          * different storeback windows, remember to store back the previous
3887          * storeback window when we're done with the write.
3888          */
3889         if ((thyper.LowPart & (-cm_chunkSize)) !=
3890                 (offset.LowPart & (-cm_chunkSize))) {
3891                 /* they're different */
3892                 doWriteBack = 1;
3893                 writeBackOffset.HighPart = offset.HighPart;
3894                 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
3895         }
3896         
3897         *writtenp = count;
3898
3899         /* now, copy the data one buffer at a time, until we've filled the
3900          * request packet */
3901         while (1) {
3902                 /* if we've copied all the data requested, we're done */
3903                 if (count <= 0) break;
3904
3905                 /* handle over quota or out of space */
3906                 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA
3907                                    | CM_SCACHEFLAG_OUTOFSPACE)) {
3908                         *writtenp = written;
3909                         break;
3910                 }
3911                 
3912                 /* otherwise, load up a buffer of data */
3913                 thyper.HighPart = offset.HighPart;
3914                 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
3915                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3916                         /* wrong buffer */
3917                         if (bufferp) {
3918                                 lock_ReleaseMutex(&bufferp->mx);
3919                                 buf_Release(bufferp);
3920                                 bufferp = NULL;
3921                         }
3922                         lock_ReleaseMutex(&scp->mx);
3923
3924                         lock_ObtainRead(&scp->bufCreateLock);
3925                         code = buf_Get(scp, &thyper, &bufferp);
3926                         lock_ReleaseRead(&scp->bufCreateLock);
3927
3928                         lock_ObtainMutex(&bufferp->mx);
3929                         lock_ObtainMutex(&scp->mx);
3930                         if (code) goto done;
3931
3932                         bufferOffset = thyper;
3933
3934                         /* now get the data in the cache */
3935                         while (1) {
3936                                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
3937                                         CM_SCACHESYNC_NEEDCALLBACK
3938                                         | CM_SCACHESYNC_WRITE
3939                                         | CM_SCACHESYNC_BUFLOCKED);
3940                                 if (code) goto done;
3941                                 
3942                                 /* If we're overwriting the entire buffer, or
3943                                  * if we're writing at or past EOF, mark the
3944                                  * buffer as current so we don't call
3945                                  * cm_GetBuffer.  This skips the fetch from the
3946                                  * server in those cases where we're going to 
3947                                  * obliterate all the data in the buffer anyway,
3948                                  * or in those cases where there is no useful
3949                                  * data at the server to start with.
3950                                  *
3951                                  * Use minLength instead of scp->length, since
3952                                  * the latter has already been updated by this
3953                                  * call.
3954                                  */
3955                                 if (LargeIntegerGreaterThanOrEqualTo(
3956                                         bufferp->offset, minLength)
3957                                     || LargeIntegerEqualTo(offset, bufferp->offset)
3958                                        && (count >= buf_bufferSize
3959                                            || LargeIntegerGreaterThanOrEqualTo(
3960                                                LargeIntegerAdd(offset,
3961                                                    ConvertLongToLargeInteger(count)),