fixes-from-andrei-20040427
[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 //#define NOSERVICE 1
11
12 #define NOMOREFILESFIX 1
13
14 #include <afs/param.h>
15 #include <afs/stds.h>
16
17 #ifndef DJGPP
18 #include <windows.h>
19 #else
20 #include <sys/timeb.h>
21 #include <tzfile.h>
22 #endif /* !DJGPP */
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <malloc.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <time.h>
29
30 #include <osi.h>
31
32 #include "afsd.h"
33
34 #include "smb.h"
35 #include "lanahelper.h"
36
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
40
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
43
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
47 unsigned long loggedOutTime;
48 int loggedOut = 0;
49 int smbShutdownFlag = 0;
50
51 int smb_LogoffTokenTransfer;
52 unsigned long smb_LogoffTransferTimeout;
53
54 DWORD last_msg_time = 0;
55
56 long ongoingOps = 0;
57
58 unsigned int sessionGen = 0;
59
60 extern void afsi_log(char *pattern, ...);
61 extern HANDLE afsi_file;
62
63 osi_hyper_t hzero = {0, 0};
64 osi_hyper_t hones = {0xFFFFFFFF, -1};
65
66 osi_log_t *  smb_logp;
67 osi_rwlock_t smb_globalLock;
68 osi_rwlock_t smb_rctLock;
69 osi_mutex_t  smb_ListenerLock;
70  
71 char smb_LANadapter;
72 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
73
74 /* for debugging */
75 long smb_maxObsConcurrentCalls=0;
76 long smb_concurrentCalls=0;
77
78 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
79
80 smb_packet_t *smb_packetFreeListp;
81 smb_ncb_t *smb_ncbFreeListp;
82
83 int smb_NumServerThreads;
84
85 int numNCBs, numSessions;
86
87 int smb_maxVCPerServer;
88 int smb_maxMpxRequests;
89
90 #define NCBmax MAXIMUM_WAIT_OBJECTS
91 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
92 EVENT_HANDLE **NCBreturns;
93 DWORD NCBsessions[NCBmax];
94 NCB *NCBs[NCBmax];
95 struct smb_packet *bufs[NCBmax];
96
97 #define Sessionmax MAXIMUM_WAIT_OBJECTS
98 EVENT_HANDLE SessionEvents[Sessionmax];
99 unsigned short LSNs[Sessionmax];
100 int lanas[Sessionmax];
101 BOOL dead_sessions[Sessionmax];
102 LANA_ENUM lana_list;
103
104 /* for raw I/O */
105 osi_mutex_t smb_RawBufLock;
106 #ifdef DJGPP
107 #define SMB_RAW_BUFS 4
108 dos_ptr smb_RawBufs;
109 int smb_RawBufSel[SMB_RAW_BUFS];
110 #else
111 char *smb_RawBufs;
112 #endif /* DJGPP */
113
114 #define RAWTIMEOUT INFINITE
115
116 /* for raw write */
117 typedef struct raw_write_cont {
118         long code;
119         osi_hyper_t offset;
120         long count;
121 #ifndef DJGPP
122         char *buf;
123 #else
124         dos_ptr buf;
125 #endif /* DJGPP */
126         int writeMode;
127         long alreadyWritten;
128 } raw_write_cont_t;
129
130 /* dir search stuff */
131 long smb_dirSearchCounter = 1;
132 smb_dirSearch_t *smb_firstDirSearchp;
133 smb_dirSearch_t *smb_lastDirSearchp;
134
135 /* hide dot files? */
136 int smb_hideDotFiles;
137
138 /* global state about V3 protocols */
139 int smb_useV3;          /* try to negotiate V3 */
140
141 #ifndef DJGPP
142 static showErrors = 1;
143 /* MessageBox or something like it */
144 int (_stdcall *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
145 extern HANDLE WaitToTerminate;
146 #endif /* DJGPP */
147
148 /* GMT time info:
149  * Time in Unix format of midnight, 1/1/1970 local time.
150  * When added to dosUTime, gives Unix (AFS) time.
151  */
152 long smb_localZero;
153
154 /* Time difference for converting to kludge-GMT */
155 int smb_NowTZ;
156
157 char *smb_localNamep = NULL;
158
159 smb_vc_t *smb_allVCsp;
160
161 smb_username_t *usernamesp = NULL;
162
163 smb_waitingLock_t *smb_allWaitingLocks;
164
165 /* forward decl */
166 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
167                                                 NCB *ncbp, raw_write_cont_t *rwcp);
168 void smb_NetbiosInit();
169 #ifdef DJGPP
170 #ifndef AFS_WIN95_ENV
171 DWORD smb_ServerExceptionFilter(void);
172 #endif
173
174 extern char cm_HostName[];
175 extern char cm_confDir[];
176 #endif
177
178 #ifdef DJGPP
179 #define LPTSTR char *
180 #define GetComputerName(str, sizep) \
181        strcpy((str), cm_HostName); \
182        *(sizep) = strlen(cm_HostName)
183 #endif /* DJGPP */
184
185 extern char AFSConfigKeyName[];
186
187 /*
188  * Demo expiration
189  *
190  * To build an expiring version, comment out the definition of NOEXPIRE,
191  * and set the definition of EXPIREDATE to the desired value.
192  */
193 #define NOEXPIRE 1
194 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
195
196
197 char * myCrt_Dispatch(int i)
198 {
199         switch (i)
200         {
201         default:
202                 return "unknown SMB op";
203         case 0x00:
204                 return "(00)ReceiveCoreMakeDir";
205         case 0x01:
206                 return "(01)ReceiveCoreRemoveDir";
207         case 0x02:
208                 return "(02)ReceiveCoreOpen";
209         case 0x03:
210                 return "(03)ReceiveCoreCreate";
211         case 0x04:
212                 return "(04)ReceiveCoreClose";
213         case 0x05:
214                 return "(05)ReceiveCoreFlush";
215         case 0x06:
216                 return "(06)ReceiveCoreUnlink";
217         case 0x07:
218                 return "(07)ReceiveCoreRename";
219         case 0x08:
220                 return "(08)ReceiveCoreGetFileAttributes";
221         case 0x09:
222                 return "(09)ReceiveCoreSetFileAttributes";
223         case 0x0a:
224                 return "(0a)ReceiveCoreRead";
225         case 0x0b:
226                 return "(0b)ReceiveCoreWrite";
227         case 0x0c:
228                 return "(0c)ReceiveCoreLockRecord";
229         case 0x0d:
230                 return "(0d)ReceiveCoreUnlockRecord";
231         case 0x0e:
232                 return "(0e)SendCoreBadOp";
233         case 0x0f:
234                 return "(0f)ReceiveCoreCreate";
235         case 0x10:
236                 return "(10)ReceiveCoreCheckPath";
237         case 0x11:
238                 return "(11)SendCoreBadOp";
239         case 0x12:
240                 return "(12)ReceiveCoreSeek";
241         case 0x1a:
242                 return "(1a)ReceiveCoreReadRaw";
243         case 0x1d:
244                 return "(1d)ReceiveCoreWriteRawDummy";
245         case 0x22:
246                 return "(22)ReceiveV3SetAttributes";
247         case 0x23:
248                 return "(23)ReceiveV3GetAttributes";
249         case 0x24:
250                 return "(24)ReceiveV3LockingX";
251         case 0x29:
252                 return "(29)SendCoreBadOp";
253         case 0x2b:
254                 return "(2b)ReceiveCoreEcho";
255         case 0x2d:
256                 return "(2d)ReceiveV3OpenX";
257         case 0x2e:
258                 return "(2e)ReceiveV3ReadX";
259         case 0x32:
260                 return "(32)ReceiveV3Tran2A";
261         case 0x33:
262                 return "(33)ReceiveV3Tran2A";
263         case 0x34:
264                 return "(34)ReceiveV3FindClose";
265         case 0x35:
266                 return "(35)ReceiveV3FindNotifyClose";
267         case 0x70:
268                 return "(70)ReceiveCoreTreeConnect";
269         case 0x71:
270                 return "(71)ReceiveCoreTreeDisconnect";
271         case 0x72:
272                 return "(72)ReceiveNegotiate";
273         case 0x73:
274                 return "(73)ReceiveV3SessionSetupX";
275         case 0x74:
276                 return "(74)ReceiveV3UserLogoffX";
277         case 0x75:
278                 return "(75)ReceiveV3TreeConnectX";
279         case 0x80:
280                 return "(80)ReceiveCoreGetDiskAttributes";
281         case 0x81:
282                 return "(81)ReceiveCoreSearchDir";
283         case 0xA0:
284                 return "(A0)ReceiveNTTransact";
285         case 0xA2:
286                 return "(A2)ReceiveNTCreateX";
287         case 0xA4:
288                 return "(A4)ReceiveNTCancel";
289         case 0xc0:
290                 return "(c0)SendCoreBadOp";
291         case 0xc1:
292                 return "(c1)SendCoreBadOp";
293         case 0xc2:
294                 return "(c2)SendCoreBadOp";
295         case 0xc3:
296                 return "(c3)SendCoreBadOp";
297         }
298 }
299
300 char * myCrt_2Dispatch(int i)
301 {
302         switch (i)
303         {
304         default:
305                 return "unknown SMB op-2";
306         case 0:
307                 return "S(00)CreateFile";
308         case 1:
309                 return "S(01)FindFirst";
310         case 2:
311                 return "S(02)FindNext"; /* FindNext */
312         case 3:
313                 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
314         case 4:
315                 return "S(04)??";
316         case 5:
317                 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
318         case 6:
319                 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
320         case 7:
321                 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
322         case 8:
323                 return "S(08)??_ReceiveTran2SetFileInfo";
324         case 9:
325                 return "S(09)??_ReceiveTran2FSCTL";
326         case 10:
327                 return "S(0a)_ReceiveTran2IOCTL";
328         case 11:
329                 return "S(0b)_ReceiveTran2FindNotifyFirst";
330         case 12:
331                 return "S(0c)_ReceiveTran2FindNotifyNext";
332         case 13:
333                 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
334         }
335 }
336
337 /* scache must be locked */
338 unsigned int smb_Attributes(cm_scache_t *scp)
339 {
340         unsigned int attrs;
341
342         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
343                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
344                 attrs = SMB_ATTR_DIRECTORY;
345         else
346                 attrs = 0;
347
348         /*
349          * We used to mark a file RO if it was in an RO volume, but that
350          * turns out to be impolitic in NT.  See defect 10007.
351          */
352 #ifdef notdef
353         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
354 #endif
355         if ((scp->unixModeBits & 0222) == 0)
356                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
357
358         return attrs;
359 }
360
361 /* Check if the named file/dir is a dotfile/dotdir */
362 /* String pointed to by lastComp can have leading slashes, but otherwise should have
363    no other patch components */
364 unsigned int smb_IsDotFile(char *lastComp) {
365         char *s;
366         if(lastComp) {
367                 /* skip over slashes */
368         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
369         }
370         else
371                 return 0;
372
373     /* nulls, curdir and parent dir doesn't count */
374         if(!*s) return 0;
375         if(*s == '.') {
376                 if(!*(s + 1)) return 0;
377                 if(*(s+1) == '.' && !*(s + 2)) return 0;
378                 return 1;
379         }
380         return 0;
381 }
382
383 static int ExtractBits(WORD bits, short start, short len)
384 {
385         int end;
386         WORD num;
387
388         end = start + len;
389         
390         num = bits << (16 - end);
391         num = num >> ((16 - end) + start);
392
393         return (int)num;
394 }
395
396 #ifndef DJGPP
397 void ShowUnixTime(char *FuncName, long unixTime)
398 {
399         FILETIME ft;
400         WORD wDate, wTime;
401
402         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
403                 
404         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
405                 osi_Log1(smb_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
406         else {
407                 int day, month, year, sec, min, hour;
408                 char msg[256];
409
410                 day = ExtractBits(wDate, 0, 5);
411                 month = ExtractBits(wDate, 5, 4);
412                 year = ExtractBits(wDate, 9, 7) + 1980;
413
414                 sec = ExtractBits(wTime, 0, 5);
415                 min = ExtractBits(wTime, 5, 6);
416                 hour = ExtractBits(wTime, 11, 5);
417
418                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
419                 osi_Log1(smb_logp, "%s", osi_LogSaveString(smb_logp, msg));
420         }
421 }
422 #endif /* DJGPP */
423
424 #ifndef DJGPP
425 /* Determine if we are observing daylight savings time */
426 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
427 {
428         TIME_ZONE_INFORMATION timeZoneInformation;
429         SYSTEMTIME utc, local, localDST;
430
431         /* Get the time zone info. NT uses this to calc if we are in DST. */
432         GetTimeZoneInformation(&timeZoneInformation);
433  
434         /* Return the daylight bias */
435         *pDstBias = timeZoneInformation.DaylightBias;
436
437         /* Return the bias */
438         *pBias = timeZoneInformation.Bias;
439
440         /* Now determine if DST is being observed */
441
442         /* Get the UTC (GMT) time */
443         GetSystemTime(&utc);
444
445         /* Convert UTC time to local time using the time zone info.  If we are
446            observing DST, the calculated local time will include this. 
447         */
448         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
449
450         /* Set the daylight bias to 0.  The daylight bias is the amount of change
451            in time that we use for daylight savings time.  By setting this to 0
452            we cause there to be no change in time during daylight savings time. 
453         */
454         timeZoneInformation.DaylightBias = 0;
455
456         /* Convert the utc time to local time again, but this time without any
457            adjustment for daylight savings time. 
458         */
459         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
460
461         /* If the two times are different, then it means that the localDST that
462            we calculated includes the daylight bias, and therefore we are
463            observing daylight savings time.
464         */
465         *pDST = localDST.wHour != local.wHour;
466 }
467 #else
468 /* Determine if we are observing daylight savings time */
469 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
470 {
471         struct timeb t;
472
473         ftime(&t);
474         *pDST = t.dstflag;
475         *pDstBias = -60;    /* where can this be different? */
476         *pBias = t.timezone;
477 }
478 #endif /* DJGPP */
479  
480
481 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
482 {
483         BOOL dst;       /* Will be TRUE if observing DST */
484         LONG dstBias;   /* Offset from local time if observing DST */
485         LONG bias;      /* Offset from GMT for local time */
486
487         /*
488          * This function will adjust the last write time to compensate
489          * for two bugs in the smb client:
490          *
491          *    1) During Daylight Savings Time, the LastWriteTime is ahead
492          *       in time by the DaylightBias (ignoring the sign - the
493          *       DaylightBias is always stored as a negative number).  If
494          *       the DaylightBias is -60, then the LastWriteTime will be
495          *       ahead by 60 minutes.
496          *
497          *    2) If the local time zone is a positive offset from GMT, then
498          *       the LastWriteTime will be the correct local time plus the
499          *       Bias (ignoring the sign - a positive offset from GMT is
500          *       always stored as a negative Bias).  If the Bias is -120,
501          *       then the LastWriteTime will be ahead by 120 minutes.
502          *
503          *    These bugs can occur at the same time.
504          */
505
506         GetTimeZoneInfo(&dst, &dstBias, &bias);
507
508         /* First adjust for DST */
509         if (dst)
510                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
511
512         /* Now adjust for a positive offset from GMT (a negative bias). */
513         if (bias < 0)
514                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
515 }               
516
517 /*
518  * Calculate the difference (in seconds) between local time and GMT.
519  * This enables us to convert file times to kludge-GMT.
520  */
521 static void
522 smb_CalculateNowTZ()
523 {
524         time_t t;
525         struct tm gmt_tm, local_tm;
526         int days, hours, minutes, seconds;
527
528         t = time(NULL);
529         gmt_tm = *(gmtime(&t));
530         local_tm = *(localtime(&t));
531
532         days = local_tm.tm_yday - gmt_tm.tm_yday;
533         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour
534 #ifdef COMMENT
535         /* There is a problem with DST immediately after the time change
536          * which may continue to exist until the machine is rebooted
537          */
538         - (local_tm.tm_isdst ? 1 : 0)
539 #endif /* COMMENT */
540         ;
541         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
542         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
543
544         smb_NowTZ = seconds;
545 }
546
547 #ifndef DJGPP
548 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
549 {
550         struct tm *ltp;
551         SYSTEMTIME stm;
552         struct tm localJunk;
553         long ersatz_unixTime;
554
555         /*
556          * Must use kludge-GMT instead of real GMT.
557          * kludge-GMT is computed by adding time zone difference to localtime.
558          *
559          * real GMT would be:
560          * ltp = gmtime(&unixTime);
561          */
562         ersatz_unixTime = unixTime - smb_NowTZ;
563         ltp = localtime(&ersatz_unixTime);
564
565         /* if we fail, make up something */
566         if (!ltp) {
567                 ltp = &localJunk;
568                 localJunk.tm_year = 89 - 20;
569                 localJunk.tm_mon = 4;
570                 localJunk.tm_mday = 12;
571                 localJunk.tm_hour = 0;
572                 localJunk.tm_min = 0;
573                 localJunk.tm_sec = 0;
574         }
575
576         stm.wYear = ltp->tm_year + 1900;
577         stm.wMonth = ltp->tm_mon + 1;
578         stm.wDayOfWeek = ltp->tm_wday;
579         stm.wDay = ltp->tm_mday;
580         stm.wHour = ltp->tm_hour;
581         stm.wMinute = ltp->tm_min;
582         stm.wSecond = ltp->tm_sec;
583         stm.wMilliseconds = 0;
584
585         SystemTimeToFileTime(&stm, largeTimep);
586 }
587 #else /* DJGPP */
588 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
589 {
590         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
591         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
592         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
593         LARGE_INTEGER ut;
594         int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
595
596         /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
597         *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
598                                    * 24 * 60);
599         *ft = LargeIntegerMultiplyByLong(*ft, 60);
600         *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
601
602         /* add unix time */
603         ut = ConvertLongToLargeInteger(unixTime);
604         ut = LargeIntegerMultiplyByLong(ut, 10000000);
605         *ft = LargeIntegerAdd(*ft, ut);
606 }
607 #endif /* !DJGPP */
608
609 #ifndef DJGPP
610 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
611 {
612         SYSTEMTIME stm;
613         struct tm lt;
614         long save_timezone;
615
616         FileTimeToSystemTime(largeTimep, &stm);
617
618         lt.tm_year = stm.wYear - 1900;
619         lt.tm_mon = stm.wMonth - 1;
620         lt.tm_wday = stm.wDayOfWeek;
621         lt.tm_mday = stm.wDay;
622         lt.tm_hour = stm.wHour;
623         lt.tm_min = stm.wMinute;
624         lt.tm_sec = stm.wSecond;
625         lt.tm_isdst = -1;
626
627         save_timezone = _timezone;
628         _timezone += smb_NowTZ;
629         *unixTimep = mktime(&lt);
630         _timezone = save_timezone;
631 }
632 #else /* DJGPP */
633 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
634 {
635         /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
636         /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
637         LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
638         LARGE_INTEGER a;
639         int leap_years = 89;
640
641         /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
642         a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60);
643         a = LargeIntegerMultiplyByLong(a, 60);
644         a = LargeIntegerMultiplyByLong(a, 10000000);
645
646         /* subtract it from ft */
647         a = LargeIntegerSubtract(*ft, a);
648
649         /* divide down to seconds */
650         *unixTimep = LargeIntegerDivideByLong(a, 10000000);
651 }
652 #endif /* !DJGPP */
653
654 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
655 {
656         struct tm *ltp;
657         int dosDate;
658         int dosTime;
659         struct tm localJunk;
660
661         ltp = localtime((time_t*) &unixTime);
662
663         /* if we fail, make up something */
664         if (!ltp) {
665                 ltp = &localJunk;
666                 localJunk.tm_year = 89 - 20;
667                 localJunk.tm_mon = 4;
668                 localJunk.tm_mday = 12;
669                 localJunk.tm_hour = 0;
670                 localJunk.tm_min = 0;
671                 localJunk.tm_sec = 0;
672         }       
673
674         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
675         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
676         *dosTimep = (dosDate<<16) | dosTime;
677 }       
678
679 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
680 {
681         unsigned short dosDate;
682         unsigned short dosTime;
683         struct tm localTm;
684         
685         dosDate = searchTime & 0xffff;
686         dosTime = (searchTime >> 16) & 0xffff;
687         
688         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
689         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
690         localTm.tm_mday = (dosDate) & 0x1f;
691         localTm.tm_hour = (dosTime>>11) & 0x1f;
692         localTm.tm_min = (dosTime >> 5) & 0x3f;
693         localTm.tm_sec = (dosTime & 0x1f) * 2;
694         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
695
696         *unixTimep = mktime(&localTm);
697 }
698
699 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
700 {
701         *dosUTimep = unixTime - smb_localZero;
702 }
703
704 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
705 {
706 #ifndef DJGPP
707         *unixTimep = dosTime + smb_localZero;
708 #else /* DJGPP */
709         /* dosTime seems to be already adjusted for GMT */
710         *unixTimep = dosTime;
711 #endif /* !DJGPP */
712 }
713
714 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
715 {
716         smb_vc_t *vcp;
717
718         lock_ObtainWrite(&smb_rctLock);
719         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
720                 if (lsn == vcp->lsn && lana == vcp->lana) {
721                         vcp->refCount++;
722                         break;
723                 }
724         }
725         if (!vcp && (flags & SMB_FLAG_CREATE)) {
726                 vcp = malloc(sizeof(*vcp));
727                 memset(vcp, 0, sizeof(*vcp));
728                 vcp->refCount = 1;
729                 vcp->tidCounter = 1;
730                 vcp->fidCounter = 1;
731                 vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
732                 vcp->nextp = smb_allVCsp;
733                 smb_allVCsp = vcp;
734                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
735                 vcp->lsn = lsn;
736                 vcp->lana = lana;
737         }
738         lock_ReleaseWrite(&smb_rctLock);
739         return vcp;
740 }
741
742 int smb_IsStarMask(char *maskp)
743 {
744         int i;
745         char tc;
746         
747         for(i=0; i<11; i++) {
748                 tc = *maskp++;
749                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
750         }       
751         return 0;
752 }
753
754 void smb_ReleaseVC(smb_vc_t *vcp)
755 {
756         lock_ObtainWrite(&smb_rctLock);
757         osi_assert(vcp->refCount-- > 0);
758         lock_ReleaseWrite(&smb_rctLock);
759 }
760
761 void smb_HoldVC(smb_vc_t *vcp)
762 {
763         lock_ObtainWrite(&smb_rctLock);
764         vcp->refCount++;
765         lock_ReleaseWrite(&smb_rctLock);
766 }
767
768 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
769 {
770         smb_tid_t *tidp;
771
772         lock_ObtainWrite(&smb_rctLock);
773         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
774                 if (tid == tidp->tid) {
775                         tidp->refCount++;
776                         break;
777                 }       
778         }
779         if (!tidp && (flags & SMB_FLAG_CREATE)) {
780                 tidp = malloc(sizeof(*tidp));
781                 memset(tidp, 0, sizeof(*tidp));
782                 tidp->nextp = vcp->tidsp;
783                 tidp->refCount = 1;
784                 tidp->vcp = vcp;
785                 vcp->tidsp = tidp;
786                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
787                 tidp->tid = tid;
788         }
789         lock_ReleaseWrite(&smb_rctLock);
790         return tidp;
791 }       
792
793 void smb_ReleaseTID(smb_tid_t *tidp)
794 {
795         smb_tid_t *tp;
796         smb_tid_t **ltpp;
797         cm_user_t *userp;
798
799         userp = NULL;
800         lock_ObtainWrite(&smb_rctLock);
801         osi_assert(tidp->refCount-- > 0);
802         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
803                 ltpp = &tidp->vcp->tidsp;
804                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
805                         if (tp == tidp) break;
806                 }
807                 osi_assert(tp != NULL);
808                 *ltpp = tp->nextp;
809                 lock_FinalizeMutex(&tidp->mx);
810                 userp = tidp->userp;    /* remember to drop ref later */
811         }
812         lock_ReleaseWrite(&smb_rctLock);
813         if (userp) {
814                 cm_ReleaseUser(userp);
815         }       
816 }       
817
818 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
819 {
820         smb_user_t *uidp = NULL;
821
822         lock_ObtainWrite(&smb_rctLock);
823         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
824                 if (uid == uidp->userID) {
825                         uidp->refCount++;
826                         osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp) ? uidp->unp->name : "");
827                 break;
828                 }
829         }
830         if (!uidp && (flags & SMB_FLAG_CREATE)) {
831                 uidp = malloc(sizeof(*uidp));
832                 memset(uidp, 0, sizeof(*uidp));
833                 uidp->nextp = vcp->usersp;
834                 uidp->refCount = 1;
835                 uidp->vcp = vcp;
836                 vcp->usersp = uidp;
837                 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
838                 uidp->userID = uid;
839                 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
840         }
841         lock_ReleaseWrite(&smb_rctLock);
842         return uidp;
843 }       
844
845 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
846 {
847         smb_username_t *unp= NULL;
848
849         lock_ObtainWrite(&smb_rctLock);
850         for(unp = usernamesp; unp; unp = unp->nextp) {
851                 if (stricmp(unp->name, usern) == 0 &&
852                         stricmp(unp->machine, machine) == 0) {
853                         unp->refCount++;
854                         break;
855                 }
856         }
857         if (!unp && (flags & SMB_FLAG_CREATE)) {
858                 unp = malloc(sizeof(*unp));
859                 memset(unp, 0, sizeof(*unp));
860                 unp->refCount = 1;
861                 unp->nextp = usernamesp;
862                 unp->name = strdup(usern);
863                 unp->machine = strdup(machine);
864                 usernamesp = unp;
865                 lock_InitializeMutex(&unp->mx, "username_t mutex");
866         }
867         lock_ReleaseWrite(&smb_rctLock);
868         return unp;
869 }       
870
871 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
872 {
873         smb_user_t *uidp= NULL;
874
875         lock_ObtainWrite(&smb_rctLock);
876         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
877                 if (!uidp->unp) 
878             continue;
879                 if (stricmp(uidp->unp->name, usern) == 0) {
880             uidp->refCount++;
881                         osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
882             break;
883                 } else
884             continue;
885         }       
886         lock_ReleaseWrite(&smb_rctLock);
887         return uidp;
888 }
889 void smb_ReleaseUID(smb_user_t *uidp)
890 {
891         smb_user_t *up;
892         smb_user_t **lupp;
893         cm_user_t *userp;
894
895         userp = NULL;
896         lock_ObtainWrite(&smb_rctLock);
897         osi_assert(uidp->refCount-- > 0);
898         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
899                 lupp = &uidp->vcp->usersp;
900                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
901                         if (up == uidp) break;
902                 }
903                 osi_assert(up != NULL);
904                 *lupp = up->nextp;
905                 lock_FinalizeMutex(&uidp->mx);
906                 if (uidp->unp) {
907                         userp = uidp->unp->userp;       /* remember to drop ref later */
908             uidp->unp->userp = NULL;
909         }
910         }               
911         lock_ReleaseWrite(&smb_rctLock);
912         if (userp) {
913                 cm_ReleaseUserVCRef(userp);
914                 cm_ReleaseUser(userp);
915         }       
916 }       
917
918 /* retrieve a held reference to a user structure corresponding to an incoming
919  * request.
920  * corresponding release function is cm_ReleaseUser.
921  */
922 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
923 {
924         smb_user_t *uidp;
925         cm_user_t *up;
926         smb_t *smbp;
927
928         smbp = (smb_t *) inp;
929         uidp = smb_FindUID(vcp, smbp->uid, 0);
930         if ((!uidp) ||  (!uidp->unp))
931                 return NULL;
932         
933         lock_ObtainMutex(&uidp->mx);
934         up = uidp->unp->userp;
935         cm_HoldUser(up);
936         lock_ReleaseMutex(&uidp->mx);
937
938         smb_ReleaseUID(uidp);
939         
940         return up;
941 }
942
943 /*
944  * Return a pointer to a pathname extracted from a TID structure.  The
945  * TID structure is not held; assume it won't go away.
946  */
947 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
948 {
949         smb_tid_t *tidp;
950         char *tpath;
951
952         tidp = smb_FindTID(vcp, tid, 0);
953     if (!tidp) 
954         return NULL;
955         tpath = tidp->pathname;
956         smb_ReleaseTID(tidp);
957         return tpath;
958 }
959
960 /* check to see if we have a chained fid, that is, a fid that comes from an
961  * OpenAndX message that ran earlier in this packet.  In this case, the fid
962  * field in a read, for example, request, isn't set, since the value is
963  * supposed to be inherited from the openAndX call.
964  */
965 int smb_ChainFID(int fid, smb_packet_t *inp)
966 {
967         if (inp->fid == 0 || inp->inCount == 0) 
968                 return fid;
969         else 
970                 return inp->fid;
971 }
972
973 /* are we a priv'd user?  What does this mean on NT? */
974 int smb_SUser(cm_user_t *userp)
975 {
976         return 1;
977 }
978
979 /* find a file ID.  If pass in 0, we'll allocate on on a create operation. */
980 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
981 {
982         smb_fid_t *fidp;
983         int newFid;
984         
985         lock_ObtainWrite(&smb_rctLock);
986         /* figure out if we need to allocate a new file ID */
987         if (fid == 0) {
988                 newFid = 1;
989                 fid = vcp->fidCounter;
990         }
991         else newFid = 0;
992
993 retry:
994         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
995                 if (fid == fidp->fid) {
996                         if (newFid) {
997                                 fid++;
998                 if (fid == 0) 
999                                         fid = 1;
1000                 goto retry;
1001             }
1002                         fidp->refCount++;
1003             break;
1004                 }
1005     }
1006     if (!fidp && (flags & SMB_FLAG_CREATE)) {
1007         char eventName[MAX_PATH];
1008         sprintf(eventName,"fid_t event fid=%d", fid);
1009                 fidp = malloc(sizeof(*fidp));
1010         memset(fidp, 0, sizeof(*fidp));
1011                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1012         fidp->refCount = 1;
1013         fidp->vcp = vcp;
1014         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1015         fidp->fid = fid;
1016                 fidp->curr_chunk = fidp->prev_chunk = -2;
1017                 fidp->raw_write_event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1018         if ( GetLastError() == ERROR_ALREADY_EXISTS )
1019             afsi_log("Event Object Already Exists: %s", eventName);
1020         if (newFid) {
1021                         vcp->fidCounter = fid+1;
1022             if (vcp->fidCounter == 0) 
1023                 vcp->fidCounter = 1;
1024         }
1025     }
1026     lock_ReleaseWrite(&smb_rctLock);
1027     return fidp;
1028 }
1029
1030 void smb_ReleaseFID(smb_fid_t *fidp)
1031 {
1032         cm_scache_t *scp;
1033     smb_vc_t *vcp;
1034     smb_ioctl_t *ioctlp;
1035
1036     if (!fidp)
1037         return;
1038
1039         scp = NULL;
1040         lock_ObtainWrite(&smb_rctLock);
1041         osi_assert(fidp->refCount-- > 0);
1042     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1043                 vcp = fidp->vcp;
1044                 if (!(fidp->flags & SMB_FID_IOCTL))
1045                         scp = fidp->scp;
1046                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1047                 thrd_CloseHandle(fidp->raw_write_event);
1048
1049                 /* and see if there is ioctl stuff to free */
1050         ioctlp = fidp->ioctlp;
1051         if (ioctlp) {
1052                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1053                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1054                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1055                         free(ioctlp);
1056         }
1057
1058         free(fidp);
1059     }
1060         lock_ReleaseWrite(&smb_rctLock);
1061
1062         /* now release the scache structure */
1063         if (scp) 
1064                 cm_ReleaseSCache(scp);
1065 }
1066
1067 /*
1068  * Case-insensitive search for one string in another;
1069  * used to find variable names in submount pathnames.
1070  */
1071 static char *smb_stristr(char *str1, char *str2)
1072 {
1073         char *cursor;
1074
1075         for (cursor = str1; *cursor; cursor++)
1076                 if (stricmp(cursor, str2) == 0)
1077                         return cursor;
1078
1079         return NULL;
1080 }
1081
1082 /*
1083  * Substitute a variable value for its name in a submount pathname.  Variable
1084  * name has been identified by smb_stristr() and is in substr.  Variable name
1085  * length (plus one) is in substr_size.  Variable value is in newstr.
1086  */
1087 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1088         char *newstr)
1089 {
1090         char temp[1024];
1091
1092         strcpy(temp, substr + substr_size - 1);
1093         strcpy(substr, newstr);
1094         strcat(str1, temp);
1095 }
1096
1097 char VNUserName[] = "%USERNAME%";
1098 char VNLCUserName[] = "%LCUSERNAME%";
1099 char VNComputerName[] = "%COMPUTERNAME%";
1100 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1101
1102 /* List available shares */
1103 int smb_ListShares()
1104 {
1105         char sbmtpath[256];
1106         char pathName[256];
1107         char shareBuf[4096];
1108         int num_shares=0;
1109         char *this_share;
1110         int len;
1111         char *p;
1112         int print_afs = 0;
1113         int code;
1114
1115         /*strcpy(shareNameList[num_shares], "all");
1116          strcpy(pathNameList[num_shares++], "/afs");*/
1117         fprintf(stderr, "The following shares are available:\n");
1118         fprintf(stderr, "Share Name (AFS Path)\n");
1119         fprintf(stderr, "---------------------\n");
1120         fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1121
1122 #ifndef DJGPP
1123         code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1124         if (code == 0 || code > sizeof(sbmtpath)) return -1;
1125 #else
1126         strcpy(sbmtpath, cm_confDir);
1127 #endif /* !DJGPP */
1128         strcat(sbmtpath, "/afsdsbmt.ini");
1129         len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1130                                                                    shareBuf, sizeof(shareBuf),
1131                                                                    sbmtpath);
1132         if (len == 0) {
1133                 return num_shares;
1134         }
1135
1136         this_share = shareBuf;
1137         do
1138         {
1139                 print_afs = 0;
1140                 /*strcpy(shareNameList[num_shares], this_share);*/
1141                 len = GetPrivateProfileString("AFS Submounts", this_share,
1142                                                                            NULL,
1143                                                                            pathName, 256,
1144                                                                            sbmtpath);
1145                 if (!len) 
1146                         return num_shares;
1147                 p = pathName;
1148                 if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) != 0)
1149             print_afs = 1;
1150                 while (*p) {
1151             if (*p == '\\') *p = '/';    /* change to / */
1152             p++;
1153                 }
1154
1155                 fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1156                                  smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1157                                  pathName);
1158                 num_shares++;
1159                 while (*this_share != 0) this_share++;  /* find next NUL */
1160                 this_share++;   /* skip past the NUL */
1161         } while (*this_share != 0);  /* stop at final NUL */
1162
1163         return num_shares;
1164 }
1165
1166 /* find a shareName in the table of submounts */
1167 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1168         char **pathNamep)
1169 {
1170         DWORD len;
1171         char pathName[1024];
1172         char *var;
1173         smb_user_t *uidp;
1174         char temp[1024];
1175         DWORD sizeTemp;
1176     char sbmtpath[MAX_PATH];
1177     char *p, *q;
1178         HKEY parmKey;
1179         DWORD code;
1180     DWORD allSubmount = 1;
1181
1182         if (strcmp(shareName, "IPC$") == 0) {
1183                 *pathNamep = NULL;
1184                 return 0;
1185         }
1186
1187     /* if allSubmounts == 0, only return the //mountRoot/all share 
1188      * if in fact it has been been created in the subMounts table.  
1189      * This is to allow sites that want to restrict access to the 
1190      * world to do so.
1191      */
1192         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1193                                                 0, KEY_QUERY_VALUE, &parmKey);
1194         if (code == ERROR_SUCCESS) {
1195         len = sizeof(allSubmount);
1196         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1197                                 (BYTE *) &allSubmount, &len);
1198         if (code != ERROR_SUCCESS) {
1199             allSubmount = 1;
1200         }
1201         RegCloseKey (parmKey);
1202         }
1203
1204         if (allSubmount && _stricmp(shareName, "all") == 0) {
1205                 *pathNamep = NULL;
1206                 return 1;
1207         }
1208
1209     /* In case, the all share is disabled we need to still be able
1210      * to handle ioctl requests 
1211      */
1212         if (_stricmp(shareName, "ioctl$") == 0) {
1213                 *pathNamep = strdup("/.__ioctl__");
1214                 return 1;
1215         }
1216
1217 #ifndef DJGPP
1218     strcpy(sbmtpath, "afsdsbmt.ini");
1219 #else /* DJGPP */
1220     strcpy(sbmtpath, cm_confDir);
1221     strcat(sbmtpath, "/afsdsbmt.ini");
1222 #endif /* !DJGPP */
1223         len = GetPrivateProfileString("AFS Submounts", shareName, "",
1224                                   pathName, sizeof(pathName), sbmtpath);
1225         if (len != 0 && len != sizeof(pathName) - 1) {
1226         /* We can accept either unix or PC style AFS pathnames.  Convert
1227          * Unix-style to PC style here for internal use. 
1228          */
1229         p = pathName;
1230         if (strncmp(p, cm_mountRoot, strlen(cm_mountRoot)) == 0)
1231             p += strlen(cm_mountRoot);  /* skip mount path */
1232         q = p;
1233         while (*q) {
1234             if (*q == '/') *q = '\\';    /* change to \ */
1235             q++;
1236         }
1237
1238         while (1)
1239         {
1240             if (var = smb_stristr(p, VNUserName)) {
1241                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1242                 if (uidp && uidp->unp)
1243                     smb_subst(p, var, sizeof(VNUserName),uidp->unp->name);
1244                 else
1245                     smb_subst(p, var, sizeof(VNUserName)," ");
1246                 if (uidp)
1247                     smb_ReleaseUID(uidp);
1248             }
1249             else if (var = smb_stristr(p, VNLCUserName)) 
1250             {
1251                 uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1252                 if (uidp && uidp->unp)
1253                     strcpy(temp, uidp->unp->name);
1254                 else 
1255                     strcpy(temp, " ");
1256                 _strlwr(temp);
1257                 smb_subst(p, var, sizeof(VNLCUserName), temp);
1258                 if (uidp)
1259                     smb_ReleaseUID(uidp);
1260             }
1261             else if (var = smb_stristr(p, VNComputerName)) 
1262             {
1263                 sizeTemp = sizeof(temp);
1264                 GetComputerName((LPTSTR)temp, &sizeTemp);
1265                 smb_subst(p, var, sizeof(VNComputerName), temp);
1266             }
1267             else if (var = smb_stristr(p, VNLCComputerName)) 
1268             {
1269                 sizeTemp = sizeof(temp);
1270                 GetComputerName((LPTSTR)temp, &sizeTemp);
1271                 _strlwr(temp);
1272                 smb_subst(p, var, sizeof(VNLCComputerName), temp);
1273             }
1274             else     
1275                 break;
1276         }
1277         *pathNamep = strdup(p);
1278         return 1;
1279     } 
1280     else /* create  \\<netbiosName>\<cellname>  */
1281     {
1282         char * p = shareName; 
1283         int rw = 0;
1284
1285         if ( *p == '.' ) {
1286             p++;
1287             rw = 1;
1288         }
1289         /* Get the full name for this cell */
1290         code = cm_SearchCellFile(p, temp, 0, 0);
1291 #ifdef AFS_AFSDB_ENV
1292                 if (code && cm_dnsEnabled) {
1293             int ttl;
1294             code = cm_SearchCellByDNS(p, temp, &ttl, 0, 0);
1295         }
1296 #endif
1297         /* construct the path */
1298         if (code == 0) {     
1299             sprintf(pathName,rw ? "/.%s/" : "/%s/",temp);
1300             *pathNamep = strdup(strlwr(pathName));
1301             return 1;
1302         }
1303         }
1304     /* failure */
1305     *pathNamep = NULL;
1306     return 0;
1307 }
1308
1309 /* find a dir search structure by cookie value, and return it held.
1310  * Must be called with smb_globalLock held.
1311  */
1312 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1313 {
1314         smb_dirSearch_t *dsp;
1315         
1316         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1317                 if (dsp->cookie == cookie) {
1318                         if (dsp != smb_firstDirSearchp) {
1319                                 /* move to head of LRU queue, too, if we're not already there */
1320                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1321                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1322                                                 osi_QPrev(&dsp->q);
1323                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1324                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1325                                 if (!smb_lastDirSearchp)
1326                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1327                         }
1328                         dsp->refCount++;
1329                         break;
1330                 }
1331         }
1332         return dsp;
1333 }
1334
1335 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1336 {
1337         lock_ObtainWrite(&smb_globalLock);
1338         dsp->flags |= SMB_DIRSEARCH_DELETE;
1339         lock_ReleaseWrite(&smb_globalLock);
1340         lock_ObtainMutex(&dsp->mx);
1341         if(dsp->scp != NULL) {
1342                 lock_ObtainMutex(&dsp->scp->mx);
1343                 if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1344                         dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1345                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1346                     dsp->scp->bulkStatProgress = hones;
1347                 }       
1348                 lock_ReleaseMutex(&dsp->scp->mx);
1349         }       
1350         lock_ReleaseMutex(&dsp->mx);
1351 }
1352
1353 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1354 {
1355         cm_scache_t *scp;
1356         
1357         scp = NULL;
1358
1359         lock_ObtainWrite(&smb_globalLock);
1360         osi_assert(dsp->refCount-- > 0);
1361         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1362                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1363                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1364                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1365                 lock_FinalizeMutex(&dsp->mx);
1366                 scp = dsp->scp;
1367                 free(dsp);
1368         }
1369         lock_ReleaseWrite(&smb_globalLock);
1370
1371         /* do this now to avoid spurious locking hierarchy creation */
1372         if (scp) cm_ReleaseSCache(scp);
1373 }
1374
1375 /* find a dir search structure by cookie value, and return it held */
1376 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1377 {
1378         smb_dirSearch_t *dsp;
1379
1380         lock_ObtainWrite(&smb_globalLock);
1381         dsp = smb_FindDirSearchNL(cookie);
1382         lock_ReleaseWrite(&smb_globalLock);
1383         return dsp;
1384 }
1385
1386 /* GC some dir search entries, in the address space expected by the specific protocol.
1387  * Must be called with smb_globalLock held; release the lock temporarily.
1388  */
1389 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1390 void smb_GCDirSearches(int isV3)
1391 {
1392         smb_dirSearch_t *prevp;
1393         smb_dirSearch_t *tp;
1394         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1395         int victimCount;
1396         int i;
1397         
1398         victimCount = 0;        /* how many have we got so far */
1399         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1400                 /* we'll move tp from queue, so
1401                  * do this early.
1402                  */
1403                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  
1404                 /* if no one is using this guy, and we're either in the new protocol,
1405                  * or we're in the old one and this is a small enough ID to be useful
1406                  * to the old protocol, GC this guy.
1407                  */
1408                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1409                         /* hold and delete */
1410                         tp->flags |= SMB_DIRSEARCH_DELETE;
1411                         victimsp[victimCount++] = tp;
1412                         tp->refCount++;
1413                 }
1414
1415                 /* don't do more than this */
1416                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1417         }
1418         
1419         /* now release them */
1420         lock_ReleaseWrite(&smb_globalLock);
1421         for(i = 0; i < victimCount; i++) {
1422                 smb_ReleaseDirSearch(victimsp[i]);
1423         }
1424         lock_ObtainWrite(&smb_globalLock);
1425 }
1426
1427 /* function for allocating a dir search entry.  We need these to remember enough context
1428  * since we don't get passed the path from call to call during a directory search.
1429  *
1430  * Returns a held dir search structure, and bumps the reference count on the vnode,
1431  * since it saves a pointer to the vnode.
1432  */
1433 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1434 {
1435         smb_dirSearch_t *dsp;
1436         int counter;
1437         int maxAllowed;
1438
1439         lock_ObtainWrite(&smb_globalLock);
1440         counter = 0;
1441
1442         /* what's the biggest ID allowed in this version of the protocol */
1443         if (isV3) maxAllowed = 65535;
1444         else maxAllowed = 255;
1445
1446         while(1) {
1447                 /* twice so we have enough tries to find guys we GC after one pass;
1448                  * 10 extra is just in case I mis-counted.
1449                  */
1450                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1451                                                                                                         __FILE__, __LINE__);
1452                 if (smb_dirSearchCounter > maxAllowed) {        
1453                         smb_dirSearchCounter = 1;
1454                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1455                 }       
1456                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1457                 if (dsp) {
1458                         /* don't need to watch for refcount zero and deleted, since
1459                          * we haven't dropped the global lock.
1460                          */
1461                         dsp->refCount--;
1462                         ++smb_dirSearchCounter;
1463                         continue;
1464                 }       
1465                 
1466                 dsp = malloc(sizeof(*dsp));
1467                 memset(dsp, 0, sizeof(*dsp));
1468                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1469                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1470                 dsp->cookie = smb_dirSearchCounter;
1471                 ++smb_dirSearchCounter;
1472                 dsp->refCount = 1;
1473                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1474                 dsp->lastTime = osi_Time();
1475                 break;
1476         }       
1477         lock_ReleaseWrite(&smb_globalLock);
1478         return dsp;
1479 }
1480
1481 static smb_packet_t *GetPacket(void)
1482 {
1483         smb_packet_t *tbp;
1484 #ifdef DJGPP
1485         unsigned int npar, seg, tb_sel;
1486 #endif
1487
1488         lock_ObtainWrite(&smb_globalLock);
1489         tbp = smb_packetFreeListp;
1490     if (tbp) 
1491         smb_packetFreeListp = tbp->nextp;
1492         lock_ReleaseWrite(&smb_globalLock);
1493     if (!tbp) {
1494 #ifndef DJGPP
1495         tbp = calloc(65540,1);
1496 #else /* DJGPP */
1497         tbp = malloc(sizeof(smb_packet_t));
1498 #endif /* !DJGPP */
1499         tbp->magic = SMB_PACKETMAGIC;
1500                 tbp->ncbp = NULL;
1501                 tbp->vcp = NULL;
1502                 tbp->resumeCode = 0;
1503                 tbp->inCount = 0;
1504                 tbp->fid = 0;
1505                 tbp->wctp = NULL;
1506                 tbp->inCom = 0;
1507                 tbp->oddByte = 0;
1508                 tbp->ncb_length = 0;
1509                 tbp->flags = 0;
1510         tbp->spacep = NULL;
1511         
1512 #ifdef DJGPP
1513         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1514         {
1515             signed int retval =
1516                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1517             if (retval == -1) {
1518                 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1519                           npar);
1520                 osi_panic("",__FILE__,__LINE__);
1521             }
1522             else {
1523                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1524                           npar, retval);
1525                 seg = retval;
1526             }
1527         }
1528         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1529         tbp->dos_pkt_sel = tb_sel;
1530 #endif /* DJGPP */
1531         }
1532     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1533
1534     return tbp;
1535 }
1536
1537 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1538 {
1539         smb_packet_t *tbp;
1540         tbp = GetPacket();
1541         memcpy(tbp, pkt, sizeof(smb_packet_t));
1542         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1543         return tbp;
1544 }
1545
1546 static NCB *GetNCB(void)
1547 {
1548         smb_ncb_t *tbp;
1549     NCB *ncbp;
1550 #ifdef DJGPP
1551     unsigned int npar, seg, tb_sel;
1552 #endif /* DJGPP */
1553
1554         lock_ObtainWrite(&smb_globalLock);
1555         tbp = smb_ncbFreeListp;
1556     if (tbp) 
1557         smb_ncbFreeListp = tbp->nextp;
1558         lock_ReleaseWrite(&smb_globalLock);
1559     if (!tbp) {
1560 #ifndef DJGPP
1561         tbp = calloc(sizeof(*tbp),1);
1562 #else /* DJGPP */
1563         tbp = malloc(sizeof(*tbp));
1564         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1565         {
1566             signed int retval =
1567                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1568             if (retval == -1) {
1569                 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1570                           npar);
1571                 osi_panic("",__FILE__,__LINE__);
1572             } else {
1573                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1574                           npar, retval);
1575                 seg = retval;
1576             }
1577         }
1578         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1579         tbp->dos_ncb_sel = tb_sel;
1580 #endif /* !DJGPP */
1581         tbp->magic = SMB_NCBMAGIC;
1582         }
1583         
1584     osi_assert(tbp->magic == SMB_NCBMAGIC);
1585
1586         memset(&tbp->ncb, 0, sizeof(NCB));
1587     ncbp = &tbp->ncb;
1588 #ifdef DJGPP
1589     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1590 #endif /* DJGPP */
1591     return ncbp;
1592 }
1593
1594 void smb_FreePacket(smb_packet_t *tbp)
1595 {
1596     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1597         
1598     lock_ObtainWrite(&smb_globalLock);
1599         tbp->nextp = smb_packetFreeListp;
1600         smb_packetFreeListp = tbp;
1601         tbp->magic = SMB_PACKETMAGIC;
1602         tbp->ncbp = NULL;
1603         tbp->vcp = NULL;
1604         tbp->resumeCode = 0;
1605         tbp->inCount = 0;
1606         tbp->fid = 0;
1607         tbp->wctp = NULL;
1608         tbp->inCom = 0;
1609         tbp->oddByte = 0;
1610         tbp->ncb_length = 0;
1611         tbp->flags = 0;
1612     lock_ReleaseWrite(&smb_globalLock);
1613 }
1614
1615 static void FreeNCB(NCB *bufferp)
1616 {
1617         smb_ncb_t *tbp;
1618         
1619     tbp = (smb_ncb_t *) bufferp;
1620     osi_assert(tbp->magic == SMB_NCBMAGIC);
1621         
1622     lock_ObtainWrite(&smb_globalLock);
1623         tbp->nextp = smb_ncbFreeListp;
1624         smb_ncbFreeListp = tbp;
1625     lock_ReleaseWrite(&smb_globalLock);
1626 }
1627
1628 /* get a ptr to the data part of a packet, and its count */
1629 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1630 {
1631     int parmBytes;
1632     int dataBytes;
1633     unsigned char *afterParmsp;
1634
1635     parmBytes = *smbp->wctp << 1;
1636         afterParmsp = smbp->wctp + parmBytes + 1;
1637         
1638     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1639     if (nbytesp) *nbytesp = dataBytes;
1640         
1641         /* don't forget to skip the data byte count, since it follows
1642      * the parameters; that's where the "2" comes from below.
1643      */
1644     return (unsigned char *) (afterParmsp + 2);
1645 }
1646
1647 /* must set all the returned parameters before playing around with the
1648  * data region, since the data region is located past the end of the
1649  * variable number of parameters.
1650  */
1651 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1652 {
1653         unsigned char *afterParmsp;
1654
1655         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1656         
1657         *afterParmsp++ = dsize & 0xff;
1658         *afterParmsp = (dsize>>8) & 0xff;
1659 }
1660
1661 /* return the parm'th parameter in the smbp packet */
1662 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1663 {
1664         int parmCount;
1665         unsigned char *parmDatap;
1666
1667         parmCount = *smbp->wctp;
1668
1669         if (parm >= parmCount) {
1670 #ifndef DJGPP
1671         HANDLE h;
1672                 char *ptbuf[1];
1673                 char s[100];
1674                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1675                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1676                                 parm, parmCount, smbp->ncb_length);
1677                 ptbuf[0] = s;
1678                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1679                                         1, smbp->ncb_length, ptbuf, smbp);
1680                 DeregisterEventSource(h);
1681 #else /* DJGPP */
1682                 char s[100];
1683
1684                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1685                                 parm, parmCount, smbp->ncb_length);
1686                 osi_Log0(smb_logp, s);
1687 #endif /* !DJGPP */
1688                 osi_panic(s, __FILE__, __LINE__);
1689         }
1690         parmDatap = smbp->wctp + (2*parm) + 1;
1691         
1692         return parmDatap[0] + (parmDatap[1] << 8);
1693 }
1694
1695 /* return the parm'th parameter in the smbp packet */
1696 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1697 {
1698         int parmCount;
1699         unsigned char *parmDatap;
1700
1701         parmCount = *smbp->wctp;
1702
1703         if (parm * 2 + offset >= parmCount * 2) {
1704 #ifndef DJGPP
1705                 HANDLE h;
1706                 char *ptbuf[1];
1707                 char s[100];
1708                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1709                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1710                                 parm, offset, parmCount, smbp->ncb_length);
1711                 ptbuf[0] = s;
1712                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1713                                         1, smbp->ncb_length, ptbuf, smbp);
1714                 DeregisterEventSource(h);
1715 #else /* DJGPP */
1716                 char s[100];
1717                 
1718                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1719                                 "ncb len %d",
1720                                  parm, offset, parmCount, smbp->ncb_length);
1721                 osi_Log0(smb_logp, s);
1722 #endif /* !DJGPP */
1723
1724                 osi_panic(s, __FILE__, __LINE__);
1725         }
1726         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1727         
1728         return parmDatap[0] + (parmDatap[1] << 8);
1729 }
1730
1731 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1732 {
1733         char *parmDatap;
1734
1735         /* make sure we have enough slots */
1736         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1737         
1738         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1739         *parmDatap++ = parmValue & 0xff;
1740         *parmDatap = (parmValue>>8) & 0xff;
1741 }
1742
1743 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1744 {
1745         char *parmDatap;
1746
1747         /* make sure we have enough slots */
1748         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1749
1750         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1751         *parmDatap++ = parmValue & 0xff;
1752         *parmDatap++ = (parmValue>>8) & 0xff;
1753         *parmDatap++ = (parmValue>>16) & 0xff;
1754         *parmDatap++ = (parmValue>>24) & 0xff;
1755 }
1756
1757 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1758 {
1759         char *parmDatap;
1760         int i;
1761
1762         /* make sure we have enough slots */
1763         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1764
1765         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1766         for (i=0; i<8; i++)
1767                 *parmDatap++ = *parmValuep++;
1768 }
1769
1770 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1771 {
1772         char *parmDatap;
1773
1774         /* make sure we have enough slots */
1775         if (*smbp->wctp <= slot) {
1776                 if (smbp->oddByte) {
1777                         smbp->oddByte = 0;
1778                         *smbp->wctp = slot+1;
1779                 } else
1780                         smbp->oddByte = 1;
1781         }
1782
1783         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1784         *parmDatap++ = parmValue & 0xff;
1785 }
1786
1787 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1788 {
1789         char *lastSlashp;
1790         
1791         lastSlashp = strrchr(inPathp, '\\');
1792         if (lastComponentp)
1793                 *lastComponentp = lastSlashp;
1794         if (lastSlashp) {
1795                 while (1) {
1796                         if (inPathp == lastSlashp) 
1797                                 break;
1798                         *outPathp++ = *inPathp++;
1799                 }
1800                 *outPathp++ = 0;
1801         }
1802         else {
1803                 *outPathp++ = 0;
1804         }
1805 }
1806
1807 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1808 {
1809         if (*inp++ != 0x4) 
1810                 return NULL;
1811         if (chainpp) {
1812                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1813         }
1814         return inp;
1815 }
1816
1817 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1818 {
1819         int tlen;
1820
1821         if (*inp++ != 0x5) 
1822                 return NULL;
1823         tlen = inp[0] + (inp[1]<<8);
1824         inp += 2;               /* skip length field */
1825         
1826         if (chainpp) {
1827                 *chainpp = inp + tlen;
1828         }
1829         
1830         if (lengthp) 
1831                 *lengthp = tlen;
1832         
1833         return inp;
1834 }       
1835
1836 /* format a packet as a response */
1837 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1838 {
1839         smb_t *outp;
1840         smb_t *inSmbp;
1841
1842         outp = (smb_t *) op;
1843         
1844         /* zero the basic structure through the smb_wct field, and zero the data
1845          * size field, assuming that wct stays zero; otherwise, you have to 
1846          * explicitly set the data size field, too.
1847          */
1848         inSmbp = (smb_t *) inp;
1849         memset(outp, 0, sizeof(smb_t)+2);
1850         outp->id[0] = 0xff;
1851         outp->id[1] = 'S';
1852         outp->id[2] = 'M';
1853         outp->id[3] = 'B';
1854         if (inp) {
1855                 outp->com = inSmbp->com;
1856                 outp->tid = inSmbp->tid;
1857                 outp->pid = inSmbp->pid;
1858                 outp->uid = inSmbp->uid;
1859                 outp->mid = inSmbp->mid;
1860                 outp->res[0] = inSmbp->res[0];
1861                 outp->res[1] = inSmbp->res[1];
1862                 op->inCom = inSmbp->com;
1863         }
1864         outp->reb = 0x80;       /* SERVER_RESP */
1865         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1866
1867         /* copy fields in generic packet area */
1868         op->wctp = &outp->wct;
1869 }
1870
1871 /* send a (probably response) packet; vcp tells us to whom to send it.
1872  * we compute the length by looking at wct and bcc fields.
1873  */
1874 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1875 {
1876         NCB *ncbp;
1877         int extra;
1878         long code = 0;
1879         unsigned char *tp;
1880         int localNCB = 0;
1881 #ifdef DJGPP
1882         dos_ptr dos_ncb;
1883 #endif /* DJGPP */
1884         
1885         ncbp = inp->ncbp;
1886         if (ncbp == NULL) {
1887                 ncbp = GetNCB();
1888                 localNCB = 1;
1889         }
1890 #ifdef DJGPP
1891         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1892 #endif /* DJGPP */
1893  
1894         memset((char *)ncbp, 0, sizeof(NCB));
1895
1896         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
1897         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
1898         extra += tp[0] + (tp[1]<<8);
1899         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
1900         extra += 3;                     /* wct and length fields */
1901         
1902         ncbp->ncb_length = extra;       /* bytes to send */
1903         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
1904         ncbp->ncb_lana_num = vcp->lana;
1905         ncbp->ncb_command = NCBSEND;    /* op means send data */
1906 #ifndef DJGPP
1907         ncbp->ncb_buffer = (char *) inp;/* packet */
1908         code = Netbios(ncbp);
1909 #else /* DJGPP */
1910         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1911         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1912
1913         /* copy header information from virtual to DOS address space */
1914         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1915         code = Netbios(ncbp, dos_ncb);
1916 #endif /* !DJGPP */
1917         
1918         if (code != 0)
1919                 osi_Log1(smb_logp, "SendPacket failure code %d", code);
1920
1921         if (localNCB)
1922                 FreeNCB(ncbp);
1923 }
1924
1925 void smb_MapNTError(long code, unsigned long *NTStatusp)
1926 {
1927         unsigned long NTStatus;
1928
1929         /* map CM_ERROR_* errors to NT 32-bit status codes */
1930         if (code == CM_ERROR_NOSUCHCELL) {
1931                 NTStatus = 0xC000000FL; /* No such file */
1932         }
1933         else if (code == CM_ERROR_NOSUCHVOLUME) {
1934                 NTStatus = 0xC000000FL; /* No such file */
1935         }
1936         else if (code == CM_ERROR_TIMEDOUT) {
1937                 NTStatus = 0xC00000CFL; /* Sharing Paused */
1938         }
1939         else if (code == CM_ERROR_RETRY) {
1940                 NTStatus = 0xC000022DL; /* Retry */
1941         }
1942         else if (code == CM_ERROR_NOACCESS) {
1943                 NTStatus = 0xC0000022L; /* Access denied */
1944         }
1945         else if (code == CM_ERROR_READONLY) {
1946                 NTStatus = 0xC00000A2L; /* Write protected */
1947         }       
1948         else if (code == CM_ERROR_NOSUCHFILE) {
1949                 NTStatus = 0xC000000FL; /* No such file */
1950         }
1951         else if (code == CM_ERROR_NOSUCHPATH) {
1952                 NTStatus = 0xC000003AL; /* Object path not found */
1953         }               
1954         else if (code == CM_ERROR_TOOBIG) {
1955                 NTStatus = 0xC000007BL; /* Invalid image format */
1956         }
1957         else if (code == CM_ERROR_INVAL) {
1958                 NTStatus = 0xC000000DL; /* Invalid parameter */
1959         }
1960         else if (code == CM_ERROR_BADFD) {
1961                 NTStatus = 0xC0000008L; /* Invalid handle */
1962         }
1963         else if (code == CM_ERROR_BADFDOP) {
1964                 NTStatus = 0xC0000022L; /* Access denied */
1965         }
1966         else if (code == CM_ERROR_EXISTS) {
1967                 NTStatus = 0xC0000035L; /* Object name collision */
1968         }
1969         else if (code == CM_ERROR_NOTEMPTY) {
1970                 NTStatus = 0xC0000101L; /* Directory not empty */
1971         }       
1972         else if (code == CM_ERROR_CROSSDEVLINK) {
1973                 NTStatus = 0xC00000D4L; /* Not same device */
1974         }
1975         else if (code == CM_ERROR_NOTDIR) {
1976                 NTStatus = 0xC0000103L; /* Not a directory */
1977         }
1978         else if (code == CM_ERROR_ISDIR) {
1979                 NTStatus = 0xC00000BAL; /* File is a directory */
1980         }
1981         else if (code == CM_ERROR_BADOP) {
1982                 NTStatus = 0xC09820FFL; /* SMB no support */
1983         }
1984         else if (code == CM_ERROR_BADSHARENAME) {
1985                 NTStatus = 0xC00000CCL; /* Bad network name */
1986         }
1987         else if (code == CM_ERROR_NOIPC) {
1988 #ifdef COMMENT
1989                 NTStatus = 0xC0000022L; /* Access Denied */
1990 #else
1991         NTStatus = 0xC000013DL; /* Remote Resources */
1992 #endif
1993         }
1994         else if (code == CM_ERROR_CLOCKSKEW) {
1995                 NTStatus = 0xC0000133L; /* Time difference at DC */
1996         }
1997         else if (code == CM_ERROR_BADTID) {
1998                 NTStatus = 0xC0982005L; /* SMB bad TID */
1999         }
2000         else if (code == CM_ERROR_USESTD) {
2001                 NTStatus = 0xC09820FBL; /* SMB use standard */
2002         }
2003         else if (code == CM_ERROR_QUOTA) {
2004                 NTStatus = 0xC0000044L; /* Quota exceeded */
2005         }
2006         else if (code == CM_ERROR_SPACE) {
2007                 NTStatus = 0xC000007FL; /* Disk full */
2008         }
2009         else if (code == CM_ERROR_ATSYS) {
2010                 NTStatus = 0xC0000033L; /* Object name invalid */
2011         }
2012         else if (code == CM_ERROR_BADNTFILENAME) {
2013                 NTStatus = 0xC0000033L; /* Object name invalid */
2014         }
2015         else if (code == CM_ERROR_WOULDBLOCK) {
2016                 NTStatus = 0xC0000055L; /* Lock not granted */
2017         }
2018         else if (code == CM_ERROR_PARTIALWRITE) {
2019                 NTStatus = 0xC000007FL; /* Disk full */
2020         }
2021         else if (code == CM_ERROR_BUFFERTOOSMALL) {
2022                 NTStatus = 0xC0000023L; /* Buffer too small */
2023         }
2024         else {
2025                 NTStatus = 0xC0982001L; /* SMB non-specific error */
2026         }
2027
2028         *NTStatusp = NTStatus;
2029         osi_Log2(smb_logp, "SMB SEND code %x as NT %x", code, NTStatus);
2030 }
2031
2032 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
2033         unsigned char *classp)
2034 {
2035         unsigned char class;
2036         unsigned short error;
2037
2038         /* map CM_ERROR_* errors to SMB errors */
2039         if (code == CM_ERROR_NOSUCHCELL) {
2040                 class = 1;
2041                 error = 3;      /* bad path */
2042         }
2043         else if (code == CM_ERROR_NOSUCHVOLUME) {
2044                 class = 1;
2045                 error = 3;      /* bad path */
2046         }
2047         else if (code == CM_ERROR_TIMEDOUT) {
2048                 class = 2;
2049                 error = 81;     /* server is paused */
2050         }
2051         else if (code == CM_ERROR_RETRY) {
2052                 class = 2;      /* shouldn't happen */
2053                 error = 1;
2054         }
2055         else if (code == CM_ERROR_NOACCESS) {
2056                 class = 2;
2057                 error = 4;      /* bad access */
2058         }
2059         else if (code == CM_ERROR_READONLY) {
2060                 class = 3;
2061                 error = 19;     /* read only */
2062         }
2063         else if (code == CM_ERROR_NOSUCHFILE) {
2064                 class = 1;
2065                 error = 2;      /* ENOENT! */
2066         }
2067         else if (code == CM_ERROR_NOSUCHPATH) {
2068                 class = 1;
2069                 error = 3;      /* Bad path */
2070         }
2071         else if (code == CM_ERROR_TOOBIG) {
2072                 class = 1;
2073                 error = 11;     /* bad format */
2074         }
2075         else if (code == CM_ERROR_INVAL) {
2076                 class = 2;      /* server non-specific error code */
2077                 error = 1;
2078         }
2079         else if (code == CM_ERROR_BADFD) {
2080                 class = 1;
2081                 error = 6;      /* invalid file handle */
2082         }
2083         else if (code == CM_ERROR_BADFDOP) {
2084                 class = 1;      /* invalid op on FD */
2085                 error = 5;
2086         }
2087         else if (code == CM_ERROR_EXISTS) {
2088                 class = 1;
2089                 error = 80;     /* file already exists */
2090         }
2091         else if (code == CM_ERROR_NOTEMPTY) {
2092                 class = 1;
2093                 error = 5;      /* delete directory not empty */
2094         }
2095         else if (code == CM_ERROR_CROSSDEVLINK) {
2096                 class = 1;
2097                 error = 17;     /* EXDEV */
2098         }
2099         else if (code == CM_ERROR_NOTDIR) {
2100                 class = 1;      /* bad path */
2101                 error = 3;
2102         }
2103         else if (code == CM_ERROR_ISDIR) {
2104                 class = 1;      /* access denied; DOS doesn't have a good match */
2105                 error = 5;
2106         }
2107         else if (code == CM_ERROR_BADOP) {
2108                 class = 2;
2109                 error = 65535;
2110         }
2111         else if (code == CM_ERROR_BADSHARENAME) {
2112                 class = 2;
2113                 error = 6;
2114         }
2115         else if (code == CM_ERROR_NOIPC) {
2116                 class = 2;
2117                 error = 4; /* bad access */
2118         }
2119         else if (code == CM_ERROR_CLOCKSKEW) {
2120                 class = 1;      /* invalid function */
2121                 error = 1;
2122         }
2123         else if (code == CM_ERROR_BADTID) {
2124                 class = 2;
2125                 error = 5;
2126         }
2127         else if (code == CM_ERROR_USESTD) {
2128                 class = 2;
2129                 error = 251;
2130         }
2131         else if (code == CM_ERROR_REMOTECONN) {
2132                 class = 2;
2133                 error = 82;
2134         }
2135         else if (code == CM_ERROR_QUOTA) {
2136                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2137                         class = 3;
2138                         error = 39;     /* disk full */
2139                 }
2140                 else {
2141                         class = 1;
2142                         error = 5;      /* access denied */
2143                 }
2144         }
2145         else if (code == CM_ERROR_SPACE) {
2146                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2147                         class = 3;
2148                         error = 39;     /* disk full */
2149                 }
2150                 else {
2151                         class = 1;
2152                         error = 5;      /* access denied */
2153                 }
2154         }
2155         else if (code == CM_ERROR_PARTIALWRITE) {
2156                 class = 3;
2157                 error = 39;     /* disk full */
2158         }
2159         else if (code == CM_ERROR_ATSYS) {
2160                 class = 1;
2161                 error = 2;      /* ENOENT */
2162         }
2163         else if (code == CM_ERROR_WOULDBLOCK) {
2164                 class = 1;
2165                 error = 33;     /* lock conflict */
2166         }
2167         else if (code == CM_ERROR_NOFILES) {
2168                 class = 1;
2169                 error = 18;     /* no files in search */
2170         }
2171         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2172                 class = 1;
2173                 error = 183;     /* Samba uses this */
2174         }
2175         else {
2176                 class = 2;
2177                 error = 1;
2178         }
2179
2180         *scodep = error;
2181         *classp = class;
2182         osi_Log3(smb_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2183 }
2184
2185 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2186 {
2187         return CM_ERROR_BADOP;
2188 }
2189
2190 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2191 {
2192         unsigned short EchoCount, i;
2193         char *data, *outdata;
2194         int dataSize;
2195
2196         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2197
2198         for (i=1; i<=EchoCount; i++) {
2199             data = smb_GetSMBData(inp, &dataSize);
2200             smb_SetSMBParm(outp, 0, i);
2201             smb_SetSMBDataLength(outp, dataSize);
2202             outdata = smb_GetSMBData(outp, NULL);
2203             memcpy(outdata, data, dataSize);
2204             smb_SendPacket(vcp, outp);
2205         }
2206
2207         return 0;
2208 }
2209
2210 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2211 {
2212         osi_hyper_t offset;
2213         long count, minCount, finalCount;
2214         unsigned short fd;
2215         smb_fid_t *fidp;
2216         long code = 0;
2217         cm_user_t *userp = NULL;
2218     NCB *ncbp;
2219     int rc;
2220 #ifndef DJGPP
2221     char *rawBuf = NULL;
2222 #else
2223     dos_ptr rawBuf = NULL;
2224     dos_ptr dos_ncb;
2225 #endif /* DJGPP */
2226
2227         rawBuf = NULL;
2228         finalCount = 0;
2229
2230         fd = smb_GetSMBParm(inp, 0);
2231         count = smb_GetSMBParm(inp, 3);
2232         minCount = smb_GetSMBParm(inp, 4);
2233         offset.HighPart = 0;    /* too bad */
2234         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2235
2236         osi_Log3(smb_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2237              fd, offset.LowPart, count);
2238
2239         fidp = smb_FindFID(vcp, fd, 0);
2240         if (!fidp)
2241                 goto send1;
2242
2243         lock_ObtainMutex(&smb_RawBufLock);
2244         if (smb_RawBufs) {
2245                 /* Get a raw buf, from head of list */
2246                 rawBuf = smb_RawBufs;
2247 #ifndef DJGPP
2248                 smb_RawBufs = *(char **)smb_RawBufs;
2249 #else /* DJGPP */
2250         smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2251 #endif /* !DJGPP */
2252         }
2253         lock_ReleaseMutex(&smb_RawBufLock);
2254         if (!rawBuf)
2255                 goto send1a;
2256
2257     if (fidp->flags & SMB_FID_IOCTL)
2258     {
2259 #ifndef DJGPP
2260         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2261 #else
2262         rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2263 #endif
2264         if (rawBuf) {
2265             /* Give back raw buffer */
2266             lock_ObtainMutex(&smb_RawBufLock);
2267 #ifndef DJGPP
2268             *((char **) rawBuf) = smb_RawBufs;
2269 #else /* DJGPP */
2270             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2271 #endif /* !DJGPP */
2272             
2273             smb_RawBufs = rawBuf;
2274             lock_ReleaseMutex(&smb_RawBufLock);
2275         }
2276
2277         smb_ReleaseFID(fidp);
2278         return rc;
2279     }
2280         
2281     userp = smb_GetUser(vcp, inp);
2282
2283 #ifndef DJGPP
2284         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2285 #else /* DJGPP */
2286     /* have to give ReadData flag so it will treat buffer as DOS mem. */
2287     code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2288                         userp, &finalCount, TRUE /* rawFlag */);
2289 #endif /* !DJGPP */
2290
2291         if (code != 0)
2292                 goto send;
2293
2294   send:
2295     cm_ReleaseUser(userp);
2296
2297   send1a:
2298         smb_ReleaseFID(fidp);
2299
2300   send1:
2301         ncbp = outp->ncbp;
2302 #ifdef DJGPP
2303     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2304 #endif /* DJGPP */
2305         memset((char *)ncbp, 0, sizeof(NCB));
2306
2307         ncbp->ncb_length = (unsigned short) finalCount;
2308         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2309         ncbp->ncb_lana_num = vcp->lana;
2310         ncbp->ncb_command = NCBSEND;
2311         ncbp->ncb_buffer = rawBuf;
2312
2313 #ifndef DJGPP
2314         code = Netbios(ncbp);
2315 #else /* DJGPP */
2316         code = Netbios(ncbp, dos_ncb);
2317 #endif /* !DJGPP */
2318         if (code != 0)
2319                 osi_Log1(smb_logp, "ReadRaw send failure code %d", code);
2320
2321         if (rawBuf) {
2322                 /* Give back raw buffer */
2323                 lock_ObtainMutex(&smb_RawBufLock);
2324 #ifndef DJGPP
2325                 *((char **) rawBuf) = smb_RawBufs;
2326 #else /* DJGPP */
2327         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2328 #endif /* !DJGPP */
2329
2330                 smb_RawBufs = rawBuf;
2331                 lock_ReleaseMutex(&smb_RawBufLock);
2332         }
2333
2334         return 0;
2335 }
2336
2337 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2338 {
2339         return 0;
2340 }
2341
2342 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2343 {
2344         return 0;
2345 }
2346
2347 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2348 {
2349         char *namep;
2350         int coreProtoIndex;
2351         int v3ProtoIndex;
2352         int NTProtoIndex;
2353         int protoIndex;                 /* index we're using */
2354         int namex;
2355         int dbytes;
2356         int entryLength;
2357         int tcounter;
2358         char protocol_array[10][1024]; /* protocol signature of the client */
2359
2360         
2361         osi_Log1(smb_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2362                          ongoingOps - 1);
2363         if (!isGateway) {
2364                 if (active_vcp) {
2365                         DWORD now = GetCurrentTime();
2366                         if (now - last_msg_time >= 30000
2367                                 && now - last_msg_time <= 90000) {
2368                                 osi_Log1(smb_logp,
2369                                                  "Setting dead_vcp %x", active_vcp);
2370                                 dead_vcp = active_vcp;
2371                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2372                         }
2373                 }
2374         }
2375
2376         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2377
2378         namep = smb_GetSMBData(inp, &dbytes);
2379         namex = 0;
2380         tcounter = 0;
2381         coreProtoIndex = -1;            /* not found */
2382         v3ProtoIndex = -1;
2383         NTProtoIndex = -1;
2384         while(namex < dbytes) {
2385                 osi_Log1(smb_logp, "Protocol %s",
2386                                  osi_LogSaveString(smb_logp, namep+1));
2387                 strcpy(protocol_array[tcounter], namep+1);
2388
2389                 /* namep points at the first protocol, or really, a 0x02
2390                  * byte preceding the null-terminated ASCII name.
2391                  */
2392                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2393                         coreProtoIndex = tcounter;
2394                 }       
2395                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2396                         v3ProtoIndex = tcounter;
2397                 }
2398                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2399                         NTProtoIndex = tcounter;
2400                 }
2401
2402                 /* compute size of protocol entry */
2403                 entryLength = strlen(namep+1);
2404         entryLength += 2;       /* 0x02 bytes and null termination */
2405                 
2406         /* advance over this protocol entry */
2407                 namex += entryLength;
2408         namep += entryLength;
2409         tcounter++;             /* which proto entry we're looking at */
2410         }
2411 #ifndef NOMOREFILESFIX
2412         /* 
2413          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2414          * the client is running by reading the protocol signature.
2415          * ie. the order in which it sends us the protocol list.
2416          *
2417          * Special handling for Windows 2000 clients (defect 11765 )
2418      * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2419          */
2420         if (tcounter == 6) {
2421                 int i = 0;
2422                 smb_t *ip = (smb_t *) inp;
2423                 smb_t *op = (smb_t *) outp;
2424
2425                 if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2426                          (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2427                          (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2428                          (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2429                          (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2430                          (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2431                         isWindows2000 = TRUE;
2432                         osi_Log0(smb_logp, "Looks like a Windows 2000 client");
2433                         /* 
2434                          * HACK: for now - just negotiate a lower protocol till we 
2435                          * figure out which flag/flag2 or some other field 
2436                          * (capabilities maybe?) to set in order for this to work
2437                          * correctly with Windows 2000 clients (defect 11765)
2438                          */
2439                         NTProtoIndex = -1;
2440                         /* Things to try (after looking at tcpdump output could be
2441                          * setting flags and flags2 to 0x98 and 0xc853 like this
2442                          * op->reb = 0x98; op->flg2 = 0xc853;
2443                          * osi_Log2(smb_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2444                          */
2445                 }       
2446         }       
2447 #endif /* NOMOREFILESFIX */
2448
2449         if (NTProtoIndex != -1) {
2450                 protoIndex = NTProtoIndex;
2451                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2452         }
2453         else if (v3ProtoIndex != -1) {
2454                 protoIndex = v3ProtoIndex;
2455                 vcp->flags |= SMB_VCFLAG_USEV3;
2456         }       
2457         else if (coreProtoIndex != -1) {
2458                 protoIndex = coreProtoIndex;
2459                 vcp->flags |= SMB_VCFLAG_USECORE;
2460         }       
2461         else protoIndex = -1;
2462
2463         if (protoIndex == -1)
2464                 return CM_ERROR_INVAL;
2465         else if (NTProtoIndex != -1) {
2466                 smb_SetSMBParm(outp, 0, protoIndex);
2467         smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2468         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2469         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2470         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2471                 smb_SetSMBParmLong(outp, 5, 65536);     /* raw buffer size */
2472         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2473         smb_SetSMBParm(outp, 8, 1);
2474                 /* 
2475                  * Tried changing the capabilities to support for W2K - defect 117695
2476                  * Maybe something else needs to be changed here?
2477                  */
2478                 /*
2479                   if (isWindows2000) 
2480                   smb_SetSMBParmLong(outp, 9, 0x43fd);
2481                   else 
2482                   smb_SetSMBParmLong(outp, 9, 0x251);
2483                   */
2484                 /* Capabilities: *
2485                  * 32-bit error codes *
2486                  * and NT Find *
2487                  * and NT SMB's *
2488                  * and raw mode */
2489                 smb_SetSMBParmLong(outp, 9, 0x251);     
2490                 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2491                 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2492                 smb_SetSMBParm(outp, 15, 0);    /* XXX server tzone: do we need? */
2493                 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2494                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2495         }
2496         else if (v3ProtoIndex != -1) {
2497                 smb_SetSMBParm(outp, 0, protoIndex);
2498                 smb_SetSMBParm(outp, 1, 0);     /* share level security, no passwd encrypt */
2499                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2500                 smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2501                 smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2502                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2503                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2504                 smb_SetSMBParm(outp, 7, 1);
2505                 smb_SetSMBParm(outp, 8, 0);     /* XXX server time: do we need? */
2506                 smb_SetSMBParm(outp, 9, 0);     /* XXX server date: do we need? */
2507                 smb_SetSMBParm(outp, 10, 0);    /* XXX server tzone: do we need? */
2508                 smb_SetSMBParm(outp, 11, 0);    /* resvd */
2509                 smb_SetSMBParm(outp, 12, 0);    /* resvd */
2510                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2511         }
2512         else if (coreProtoIndex != -1) {
2513                 smb_SetSMBParm(outp, 0, protoIndex);
2514                 smb_SetSMBDataLength(outp, 0);
2515         }
2516         return 0;
2517 }
2518
2519 void smb_Daemon(void *parmp)
2520 {
2521         int count = 0;
2522
2523         while(1) {
2524                 count++;
2525                 thrd_Sleep(10000);
2526                 if ((count % 360) == 0)         /* every hour */
2527                         smb_CalculateNowTZ();
2528                 /* XXX GC dir search entries */
2529         }
2530 }
2531
2532 void smb_WaitingLocksDaemon()
2533 {
2534         smb_waitingLock_t *wL, *nwL;
2535         int first;
2536         smb_vc_t *vcp;
2537         smb_packet_t *inp, *outp;
2538         NCB *ncbp;
2539         long code = 0;
2540
2541         while(1) {
2542                 lock_ObtainWrite(&smb_globalLock);
2543                 nwL = smb_allWaitingLocks;
2544                 if (nwL == NULL) {
2545                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2546                         thrd_Sleep(1000);
2547                         continue;
2548                 }
2549                 else first = 1;
2550                 do {
2551                         if (first)
2552                                 first = 0;
2553                         else
2554                                 lock_ObtainWrite(&smb_globalLock);
2555                         wL = nwL;
2556                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2557                         lock_ReleaseWrite(&smb_globalLock);
2558                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2559                                                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2560                         if (code == CM_ERROR_WOULDBLOCK) {
2561                                 /* no progress */
2562                                 if (wL->timeRemaining != 0xffffffff
2563                                     && (wL->timeRemaining -= 1000) < 0)
2564                                         goto endWait;
2565                                 continue;
2566                         }
2567                   endWait:
2568                         vcp = wL->vcp;
2569                         inp = wL->inp;
2570                         outp = wL->outp;
2571                         ncbp = GetNCB();
2572                         ncbp->ncb_length = inp->ncb_length;
2573                         inp->spacep = cm_GetSpace();
2574
2575                         /* Remove waitingLock from list */
2576                         lock_ObtainWrite(&smb_globalLock);
2577                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2578                                     &wL->q);
2579                         lock_ReleaseWrite(&smb_globalLock);
2580
2581                         /* Resume packet processing */
2582                         if (code == 0)
2583                                 smb_SetSMBDataLength(outp, 0);
2584                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2585                         outp->resumeCode = code;
2586                         outp->ncbp = ncbp;
2587                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2588
2589                         /* Clean up */
2590                         cm_FreeSpace(inp->spacep);
2591                         smb_FreePacket(inp);
2592                         smb_FreePacket(outp);
2593                         FreeNCB(ncbp);
2594                         free(wL);
2595                 } while (nwL);
2596                 thrd_Sleep(1000);
2597         }
2598 }
2599
2600 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2601 {
2602         osi_Log0(smb_logp, "SMB receive get disk attributes");
2603
2604         smb_SetSMBParm(outp, 0, 32000);
2605         smb_SetSMBParm(outp, 1, 64);
2606         smb_SetSMBParm(outp, 2, 1024);
2607         smb_SetSMBParm(outp, 3, 30000);
2608         smb_SetSMBParm(outp, 4, 0);
2609         smb_SetSMBDataLength(outp, 0);
2610         return 0;
2611 }
2612
2613 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2614 {
2615         smb_tid_t *tidp;
2616         unsigned short newTid;
2617         char shareName[256];
2618         char *sharePath;
2619         int shareFound;
2620         char *tp;
2621         char *pathp;
2622         char *passwordp;
2623         cm_user_t *userp;
2624
2625         osi_Log0(smb_logp, "SMB receive tree connect");
2626
2627         /* parse input parameters */
2628         tp = smb_GetSMBData(inp, NULL);
2629         pathp = smb_ParseASCIIBlock(tp, &tp);
2630         passwordp = smb_ParseASCIIBlock(tp, &tp);
2631         tp = strrchr(pathp, '\\');
2632         if (!tp)
2633                 return CM_ERROR_BADSMB;
2634         strcpy(shareName, tp+1);
2635
2636         userp = smb_GetUser(vcp, inp);
2637
2638         lock_ObtainMutex(&vcp->mx);
2639         newTid = vcp->tidCounter++;
2640         lock_ReleaseMutex(&vcp->mx);
2641         
2642         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2643         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2644         if (!shareFound) {
2645                 smb_ReleaseTID(tidp);
2646                 return CM_ERROR_BADSHARENAME;
2647         }
2648         lock_ObtainMutex(&tidp->mx);
2649         tidp->userp = userp;
2650         tidp->pathname = sharePath;
2651         lock_ReleaseMutex(&tidp->mx);
2652         smb_ReleaseTID(tidp);
2653
2654         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2655         smb_SetSMBParm(rsp, 1, newTid);
2656         smb_SetSMBDataLength(rsp, 0);
2657
2658         osi_Log1(smb_logp, "SMB tree connect created ID %d", newTid);
2659         return 0;
2660 }
2661
2662 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2663 {
2664         int tlen;
2665
2666         if (*inp++ != 0x1) return NULL;
2667         tlen = inp[0] + (inp[1]<<8);
2668         inp += 2;               /* skip length field */
2669         
2670         if (chainpp) {
2671                 *chainpp = inp + tlen;
2672         }       
2673         
2674         if (lengthp) *lengthp = tlen;
2675         
2676         return inp;
2677 }
2678
2679 /* set maskp to the mask part of the incoming path.
2680  * Mask is 11 bytes long (8.3 with the dot elided).
2681  * Returns true if succeeds with a valid name, otherwise it does
2682  * its best, but returns false.
2683  */
2684 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2685 {
2686         char *tp;
2687         char *up;
2688         int i;
2689         int tc;
2690         int valid8Dot3;
2691
2692         /* starts off valid */
2693         valid8Dot3 = 1;
2694
2695         /* mask starts out all blanks */
2696         memset(maskp, ' ', 11);
2697
2698         /* find last backslash, or use whole thing if there is none */
2699         tp = strrchr(pathp, '\\');
2700         if (!tp) tp = pathp;
2701         else tp++;      /* skip slash */
2702         
2703         up = maskp;
2704
2705         /* names starting with a dot are illegal */
2706         if (*tp == '.') valid8Dot3 = 0;
2707
2708     for(i=0;; i++) {
2709                 tc = *tp++;
2710         if (tc == 0) return valid8Dot3;
2711         if (tc == '.' || tc == '"') break;
2712         if (i < 8) *up++ = tc;
2713         else valid8Dot3 = 0;
2714     }
2715         
2716     /* if we get here, tp point after the dot */
2717     up = maskp+8;       /* ext goes here */
2718     for(i=0;;i++) {
2719         tc = *tp++;
2720         if (tc == 0) 
2721                         return valid8Dot3;
2722
2723         /* too many dots */
2724         if (tc == '.' || tc == '"') 
2725                         valid8Dot3 = 0;
2726
2727         /* copy extension if not too long */
2728         if (i < 3) 
2729                         *up++ = tc;
2730         else 
2731                         valid8Dot3 = 0;
2732     }   
2733
2734     /* unreachable */
2735 }
2736
2737 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2738 {
2739         char umask[11];
2740         int valid;
2741         int i;
2742         char tc1;
2743         char tc2;
2744         char *tp1;
2745         char *tp2;
2746
2747         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2748
2749         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2750         if (!valid) 
2751                 return 0;
2752  
2753         /* otherwise, we have a valid 8.3 name; see if we have a match,
2754          * treating '?' as a wildcard in maskp (but not in the file name).
2755          */
2756         tp1 = umask;    /* real name, in mask format */
2757         tp2 = maskp;    /* mask, in mask format */
2758         for(i=0; i<11; i++) {
2759                 tc1 = *tp1++;   /* char from real name */
2760                 tc2 = *tp2++;   /* char from mask */
2761                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2762                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2763                 if (tc1 == tc2) 
2764                         continue;
2765                 if (tc2 == '?' && tc1 != ' ') 
2766                         continue;
2767                 if (tc2 == '>') 
2768                         continue;
2769                 return 0;
2770         }
2771
2772         /* we got a match */
2773         return 1;
2774 }
2775
2776 char *smb_FindMask(char *pathp)
2777 {
2778         char *tp;
2779         
2780         tp = strrchr(pathp, '\\');      /* find last slash */
2781
2782         if (tp) 
2783                 return tp+1;    /* skip the slash */
2784         else 
2785                 return pathp;   /* no slash, return the entire path */
2786 }
2787
2788 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2789 {
2790         unsigned char *pathp;
2791         unsigned char *tp;
2792         unsigned char mask[11];
2793         unsigned char *statBlockp;
2794         unsigned char initStatBlock[21];
2795         int statLen;
2796         
2797         osi_Log0(smb_logp, "SMB receive search volume");
2798
2799         /* pull pathname and stat block out of request */
2800         tp = smb_GetSMBData(inp, NULL);
2801         pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2802         osi_assert(pathp != NULL);
2803         statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2804         osi_assert(statBlockp != NULL);
2805         if (statLen == 0) {
2806                 statBlockp = initStatBlock;
2807                 statBlockp[0] = 8;
2808         }
2809         
2810         /* for returning to caller */
2811         smb_Get8Dot3MaskFromPath(mask, pathp);
2812         
2813         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
2814         tp = smb_GetSMBData(outp, NULL);
2815         *tp++ = 5;
2816         *tp++ = 43;     /* bytes in a dir entry */
2817         *tp++ = 0;      /* high byte in counter */
2818
2819         /* now marshall the dir entry, starting with the search status */
2820         *tp++ = statBlockp[0];          /* Reserved */
2821         memcpy(tp, mask, 11); tp += 11; /* FileName */
2822
2823         /* now pass back server use info, with 1st byte non-zero */
2824         *tp++ = 1;
2825         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
2826
2827         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
2828
2829         *tp++ = 0x8;            /* attribute: volume */
2830
2831         /* copy out time */
2832         *tp++ = 0;
2833         *tp++ = 0;
2834
2835         /* copy out date */
2836         *tp++ = 18;
2837         *tp++ = 178;
2838
2839         /* 4 byte file size */
2840         *tp++ = 0;
2841         *tp++ = 0;
2842         *tp++ = 0;
2843         *tp++ = 0;
2844
2845         /* finally, null-terminated 8.3 pathname, which we set to AFS */
2846         memset(tp, ' ', 13);
2847         strcpy(tp, "AFS");
2848
2849         /* set the length of the data part of the packet to 43 + 3, for the dir
2850          * entry plus the 5 and the length fields.
2851          */
2852         smb_SetSMBDataLength(outp, 46);
2853         return 0;
2854 }
2855
2856 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2857         cm_user_t *userp, cm_req_t *reqp)
2858 {
2859         long code = 0;
2860         cm_scache_t *scp;
2861         char *dptr;
2862         long dosTime;
2863         u_short shortTemp;
2864         char attr;
2865         smb_dirListPatch_t *patchp;
2866         smb_dirListPatch_t *npatchp;
2867
2868         for(patchp = *dirPatchespp; patchp; patchp =
2869                  (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2870                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2871                 if (code) continue;
2872                 lock_ObtainMutex(&scp->mx);
2873                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2874                                                   CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2875                 if (code) {     
2876                         lock_ReleaseMutex(&scp->mx);
2877                         cm_ReleaseSCache(scp);
2878                         continue;
2879                 }
2880                 dptr = patchp->dptr;
2881
2882                 attr = smb_Attributes(scp);
2883         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2884         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2885             attr |= SMB_ATTR_HIDDEN;
2886         *dptr++ = attr;
2887
2888                 /* get dos time */
2889                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2890                 
2891                 /* copy out time */
2892                 shortTemp = dosTime & 0xffff;
2893                 *((u_short *)dptr) = shortTemp;
2894                 dptr += 2;
2895
2896                 /* and copy out date */
2897                 shortTemp = (dosTime>>16) & 0xffff;
2898                 *((u_short *)dptr) = shortTemp;
2899                 dptr += 2;
2900                 
2901                 /* copy out file length */
2902                 *((u_long *)dptr) = scp->length.LowPart;
2903                 dptr += 4;
2904                 lock_ReleaseMutex(&scp->mx);
2905                 cm_ReleaseSCache(scp);
2906         }
2907         
2908         /* now free the patches */
2909         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2910                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2911                 free(patchp);
2912         }       
2913         
2914         /* and mark the list as empty */
2915         *dirPatchespp = NULL;
2916
2917         return code;
2918 }
2919
2920 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2921 {
2922         int attribute;
2923         long nextCookie;
2924         char *tp;
2925         long code = 0;
2926         char *pathp;
2927         cm_dirEntry_t *dep;
2928         int maxCount;
2929         smb_dirListPatch_t *dirListPatchesp;
2930         smb_dirListPatch_t *curPatchp;
2931         int dataLength;
2932         cm_buf_t *bufferp;
2933         long temp;
2934         osi_hyper_t dirLength;
2935         osi_hyper_t bufferOffset;
2936         osi_hyper_t curOffset;
2937         osi_hyper_t thyper;
2938         unsigned char *inCookiep;
2939         smb_dirSearch_t *dsp;
2940         cm_scache_t *scp;
2941         long entryInDir;
2942         long entryInBuffer;
2943         unsigned long clientCookie;
2944         cm_pageHeader_t *pageHeaderp;
2945         cm_user_t *userp = NULL;
2946         int slotInPage;
2947         char shortName[13];
2948         char *actualName;
2949         char *shortNameEnd;
2950         char mask[11];
2951         int returnedNames;
2952         long nextEntryCookie;
2953         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
2954         char resByte;                   /* reserved byte from the cookie */
2955         char *op;                       /* output data ptr */
2956         char *origOp;                   /* original value of op */
2957         cm_space_t *spacep;             /* for pathname buffer */
2958         int starPattern;
2959         int rootPath = 0;
2960         int caseFold;
2961         char *tidPathp;
2962         cm_req_t req;
2963         cm_fid_t fid;
2964         int fileType;
2965
2966         cm_InitReq(&req);
2967
2968         maxCount = smb_GetSMBParm(inp, 0);
2969
2970         dirListPatchesp = NULL;
2971         
2972         caseFold = CM_FLAG_CASEFOLD;
2973
2974         tp = smb_GetSMBData(inp, NULL);
2975         pathp = smb_ParseASCIIBlock(tp, &tp);
2976         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2977
2978         /* bail out if request looks bad */
2979         if (!tp || !pathp) {
2980                 return CM_ERROR_BADSMB;
2981         }
2982
2983         /* We can handle long names */
2984         if (vcp->flags & SMB_VCFLAG_USENT)
2985                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
2986
2987         /* make sure we got a whole search status */
2988         if (dataLength < 21) {
2989                 nextCookie = 0;         /* start at the beginning of the dir */
2990                 resByte = 0;
2991                 clientCookie = 0;
2992                 attribute = smb_GetSMBParm(inp, 1);
2993
2994                 /* handle volume info in another function */
2995                 if (attribute & 0x8)
2996                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2997
2998                 osi_Log2(smb_logp, "SMB receive search dir count %d [%s]",
2999                                  maxCount, osi_LogSaveString(smb_logp, pathp));
3000
3001                 if (*pathp == 0) {      /* null pathp, treat as root dir */
3002                         if (!(attribute & SMB_ATTR_DIRECTORY))  /* exclude dirs */
3003                                 return CM_ERROR_NOFILES;
3004                         rootPath = 1;
3005                 }
3006
3007                 dsp = smb_NewDirSearch(0);
3008                 dsp->attribute = attribute;
3009                 smb_Get8Dot3MaskFromPath(mask, pathp);
3010                 memcpy(dsp->mask, mask, 11);
3011
3012                 /* track if this is likely to match a lot of entries */
3013                 if (smb_IsStarMask(mask)) starPattern = 1;
3014                 else starPattern = 0;
3015         }       
3016         else {
3017                 /* pull the next cookie value out of the search status block */
3018                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
3019                         + (inCookiep[16]<<24);
3020                 dsp = smb_FindDirSearch(inCookiep[12]);
3021                 if (!dsp) {
3022                         /* can't find dir search status; fatal error */
3023                         return CM_ERROR_BADFD;
3024                 }
3025                 attribute = dsp->attribute;
3026                 resByte = inCookiep[0];
3027
3028                 /* copy out client cookie, in host byte order.  Don't bother
3029                  * interpreting it, since we're just passing it through, anyway.
3030                  */
3031                 memcpy(&clientCookie, &inCookiep[17], 4);
3032
3033                 memcpy(mask, dsp->mask, 11);
3034
3035                 /* assume we're doing a star match if it has continued for more
3036                  * than one call.
3037                  */
3038                 starPattern = 1;
3039         }
3040
3041         osi_Log3(smb_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
3042                          nextCookie, dsp->cookie, attribute);
3043
3044         userp = smb_GetUser(vcp, inp);
3045
3046         /* try to get the vnode for the path name next */
3047         lock_ObtainMutex(&dsp->mx);
3048         if (dsp->scp) {
3049                 scp = dsp->scp;
3050                 cm_HoldSCache(scp);
3051                 code = 0;
3052         }
3053         else {
3054                 spacep = inp->spacep;
3055                 smb_StripLastComponent(spacep->data, NULL, pathp);
3056                 lock_ReleaseMutex(&dsp->mx);
3057                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3058                 code = cm_NameI(cm_rootSCachep, spacep->data,
3059                                                 caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3060                 lock_ObtainMutex(&dsp->mx);
3061                 if (code == 0) {
3062                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3063                         dsp->scp = scp;
3064                         /* we need one hold for the entry we just stored into,
3065                          * and one for our own processing.  When we're done with this
3066                          * function, we'll drop the one for our own processing.
3067                          * We held it once from the namei call, and so we do another hold
3068                          * now.
3069                          */
3070                         cm_HoldSCache(scp);
3071                         lock_ObtainMutex(&scp->mx);
3072                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3073                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3074                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3075                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3076                         }
3077                         lock_ReleaseMutex(&scp->mx);
3078                 }
3079         }
3080         lock_ReleaseMutex(&dsp->mx);
3081         if (code) {
3082                 cm_ReleaseUser(userp);
3083                 smb_DeleteDirSearch(dsp);
3084                 smb_ReleaseDirSearch(dsp);
3085                 return code;
3086         }
3087
3088         /* reserves space for parameter; we'll adjust it again later to the
3089          * real count of the # of entries we returned once we've actually
3090          * assembled the directory listing.
3091          */
3092         smb_SetSMBParm(outp, 0, 0);
3093         
3094         /* get the directory size */
3095         lock_ObtainMutex(&scp->mx);
3096         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3097                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3098         if (code) {
3099                 lock_ReleaseMutex(&scp->mx);
3100                 cm_ReleaseSCache(scp);
3101                 cm_ReleaseUser(userp);
3102                 smb_DeleteDirSearch(dsp);
3103                 smb_ReleaseDirSearch(dsp);
3104                 return code;
3105         }
3106         
3107         dirLength = scp->length;
3108         bufferp = NULL;
3109         bufferOffset.LowPart = bufferOffset.HighPart = 0;
3110         curOffset.HighPart = 0;
3111         curOffset.LowPart = nextCookie;
3112         origOp = op = smb_GetSMBData(outp, NULL);
3113         /* and write out the basic header */
3114         *op++ = 5;              /* variable block */
3115         op += 2;                /* skip vbl block length; we'll fill it in later */
3116         code = 0;
3117         returnedNames = 0;
3118         while (1) {
3119                 /* make sure that curOffset.LowPart doesn't point to the first
3120                  * 32 bytes in the 2nd through last dir page, and that it doesn't
3121                  * point at the first 13 32-byte chunks in the first dir page,
3122                  * since those are dir and page headers, and don't contain useful
3123                  * information.
3124                  */
3125                 temp = curOffset.LowPart & (2048-1);
3126                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3127                         /* we're in the first page */
3128                         if (temp < 13*32) temp = 13*32;
3129                 }
3130                 else {
3131                         /* we're in a later dir page */
3132                         if (temp < 32) temp = 32;
3133                 }
3134                 
3135                 /* make sure the low order 5 bits are zero */
3136                 temp &= ~(32-1);
3137
3138                 /* now put temp bits back ito curOffset.LowPart */
3139                 curOffset.LowPart &= ~(2048-1);
3140                 curOffset.LowPart |= temp;
3141
3142                 /* check if we've returned all the names that will fit in the
3143                  * response packet.
3144                  */
3145                 if (returnedNames >= maxCount) 
3146                         break;
3147                 
3148                 /* check if we've passed the dir's EOF */
3149                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3150
3151                 /* see if we can use the bufferp we have now; compute in which page
3152                  * the current offset would be, and check whether that's the offset
3153                  * of the buffer we have.  If not, get the buffer.
3154                  */
3155                 thyper.HighPart = curOffset.HighPart;
3156                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3157                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3158                         /* wrong buffer */
3159                         if (bufferp) {
3160                                 buf_Release(bufferp);
3161                                 bufferp = NULL;
3162                         }       
3163                         lock_ReleaseMutex(&scp->mx);
3164                         lock_ObtainRead(&scp->bufCreateLock);
3165                         code = buf_Get(scp, &thyper, &bufferp);
3166                         lock_ReleaseRead(&scp->bufCreateLock);
3167
3168                         /* now, if we're doing a star match, do bulk fetching of all of 
3169                          * the status info for files in the dir.
3170                          */
3171                         if (starPattern) {
3172                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3173                                                                                 &req);
3174                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3175                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
3176                                                                         scp->bulkStatProgress)) {
3177                                         /* Don't bulk stat if risking timeout */
3178                                         int now = GetCurrentTime();
3179                                         if (now - req.startTime > 5000) {
3180                                                 scp->bulkStatProgress = thyper;
3181                                                 scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3182                                                 dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3183                                         } else
3184                                                 cm_TryBulkStat(scp, &thyper, userp, &req);
3185                                 }
3186                         }
3187
3188                         lock_ObtainMutex(&scp->mx);
3189                         if (code) 
3190                                 break;
3191                         bufferOffset = thyper;
3192
3193                         /* now get the data in the cache */
3194                         while (1) {
3195                                 code = cm_SyncOp(scp, bufferp, userp, &req,
3196                                                                   PRSFS_LOOKUP,
3197                                                                   CM_SCACHESYNC_NEEDCALLBACK
3198                                                                   | CM_SCACHESYNC_READ);
3199                                 if (code) break;
3200                                 
3201                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3202
3203                                 /* otherwise, load the buffer and try again */
3204                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3205                                                                         &req);
3206                                 if (code) break;
3207                         }
3208                         if (code) {
3209                                 buf_Release(bufferp);
3210                                 bufferp = NULL;
3211                                 break;
3212                         }
3213                 }       /* if (wrong buffer) ... */
3214
3215                 /* now we have the buffer containing the entry we're interested in; copy
3216                  * it out if it represents a non-deleted entry.
3217                  */
3218                 entryInDir = curOffset.LowPart & (2048-1);
3219                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3220
3221                 /* page header will help tell us which entries are free.  Page header
3222                  * can change more often than once per buffer, since AFS 3 dir page size
3223                  * may be less than (but not more than a buffer package buffer.
3224                  */
3225                 temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3226                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
3227                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3228
3229                 /* now determine which entry we're looking at in the page.  If it is
3230                  * free (there's a free bitmap at the start of the dir), we should
3231                  * skip these 32 bytes.
3232                  */
3233                 slotInPage = (entryInDir & 0x7e0) >> 5;
3234                 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3235                         /* this entry is free */
3236                         numDirChunks = 1;               /* only skip this guy */
3237                         goto nextEntry;
3238                 }
3239
3240                 tp = bufferp->datap + entryInBuffer;
3241                 dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3242
3243                 /* while we're here, compute the next entry's location, too,
3244                  * since we'll need it when writing out the cookie into the dir
3245                  * listing stream.
3246                  *
3247                  * XXXX Probably should do more sanity checking.
3248                  */
3249                 numDirChunks = cm_NameEntries(dep->name, NULL);
3250                 
3251                 /* compute the offset of the cookie representing the next entry */
3252                 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3253
3254                 /* Compute 8.3 name if necessary */
3255                 actualName = dep->name;
3256                 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3257                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3258                         actualName = shortName;
3259                 }
3260
3261                 if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3262                         /* this is one of the entries to use: it is not deleted
3263                          * and it matches the star pattern we're looking for.
3264                          */
3265
3266                         /* Eliminate entries that don't match requested
3267                            attributes */
3268
3269                         /* no hidden files */
3270                         if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3271                                 goto nextEntry;
3272
3273                         if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3274                         {
3275                                 /* We have already done the cm_TryBulkStat above */
3276                                 fid.cell = scp->fid.cell;
3277                                 fid.volume = scp->fid.volume;
3278                                 fid.vnode = ntohl(dep->fid.vnode);
3279                                 fid.unique = ntohl(dep->fid.unique);
3280                                 fileType = cm_FindFileType(&fid);
3281                                 osi_Log2(smb_logp, "smb_ReceiveCoreSearchDir: file %s "
3282                                                   "has filetype %d", dep->name,
3283                                                   fileType);
3284                                 if (fileType == CM_SCACHETYPE_DIRECTORY)
3285                                         goto nextEntry;
3286                         }
3287
3288                         *op++ = resByte;
3289                         memcpy(op, mask, 11); op += 11;
3290                         *op++ = (char) dsp->cookie;     /* they say it must be non-zero */
3291                         *op++ = nextEntryCookie & 0xff;
3292                         *op++ = (nextEntryCookie>>8) & 0xff;
3293                         *op++ = (nextEntryCookie>>16) & 0xff;
3294                         *op++ = (nextEntryCookie>>24) & 0xff;
3295                         memcpy(op, &clientCookie, 4); op += 4;
3296
3297                         /* now we emit the attribute.  This is sort of tricky,
3298                          * since we need to really stat the file to find out
3299                          * what type of entry we've got.  Right now, we're
3300                          * copying out data from a buffer, while holding the
3301                          * scp locked, so it isn't really convenient to stat
3302                          * something now.  We'll put in a place holder now,
3303                          * and make a second pass before returning this to get
3304                          * the real attributes.  So, we just skip the data for
3305                          * now, and adjust it later.  We allocate a patch
3306                          * record to make it easy to find this point later.
3307                          * The replay will happen at a time when it is safe to
3308                          * unlock the directory.
3309                          */
3310                         curPatchp = malloc(sizeof(*curPatchp));
3311                         osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3312                         curPatchp->dptr = op;
3313                         curPatchp->fid.cell = scp->fid.cell;
3314                         curPatchp->fid.volume = scp->fid.volume;
3315                         curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3316                         curPatchp->fid.unique = ntohl(dep->fid.unique);
3317
3318                         /* do hidden attribute here since name won't be around when applying
3319                          * dir list patches
3320                          */
3321
3322                         if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3323                                 curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3324                         else
3325                                 curPatchp->flags = 0;
3326
3327                         op += 9;        /* skip attr, time, date and size */
3328
3329                         /* zero out name area.  The spec says to pad with
3330                          * spaces, but Samba doesn't, and neither do we.
3331                          */
3332                         memset(op, 0, 13);
3333
3334                         /* finally, we get to copy out the name; we know that
3335                          * it fits in 8.3 or the pattern wouldn't match, but it
3336                          * never hurts to be sure.
3337                          */
3338                         strncpy(op, actualName, 13);
3339
3340                         /* Uppercase if requested by client */
3341                         if ((((smb_t *)inp)->flg2 & 1) == 0)
3342                                 _strupr(op);
3343
3344                         op += 13;
3345
3346                         /* now, adjust the # of entries copied */
3347                         returnedNames++;
3348                 }       /* if we're including this name */
3349                 
3350           nextEntry:
3351                 /* and adjust curOffset to be where the new cookie is */
3352                 thyper.HighPart = 0;
3353                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3354                 curOffset = LargeIntegerAdd(thyper, curOffset);
3355         }               /* while copying data for dir listing */
3356
3357         /* release the mutex */
3358         lock_ReleaseMutex(&scp->mx);
3359         if (bufferp) buf_Release(bufferp);
3360
3361         /* apply and free last set of patches; if not doing a star match, this
3362          * will be empty, but better safe (and freeing everything) than sorry.
3363          */
3364         smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3365
3366         /* special return code for unsuccessful search */
3367         if (code == 0 && dataLength < 21 && returnedNames == 0)
3368                 code = CM_ERROR_NOFILES;
3369
3370         osi_Log2(smb_logp, "SMB search dir done, %d names, code %d",
3371                  returnedNames, code);
3372
3373         if (code != 0) {
3374                 smb_DeleteDirSearch(dsp);
3375                 smb_ReleaseDirSearch(dsp);
3376                 cm_ReleaseSCache(scp);
3377                 cm_ReleaseUser(userp);
3378                 return code;
3379         }
3380
3381         /* finalize the output buffer */
3382         smb_SetSMBParm(outp, 0, returnedNames);
3383         temp = (long) (op - origOp);
3384         smb_SetSMBDataLength(outp, temp);
3385
3386         /* the data area is a variable block, which has a 5 (already there)
3387          * followed by the length of the # of data bytes.  We now know this to
3388          * be "temp," although that includes the 3 bytes of vbl block header.
3389          * Deduct for them and fill in the length field.
3390          */
3391         temp -= 3;              /* deduct vbl block info */
3392         osi_assert(temp == (43 * returnedNames));
3393         origOp[1] = temp & 0xff;
3394         origOp[2] = (temp>>8) & 0xff;
3395         if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3396         smb_ReleaseDirSearch(dsp);
3397         cm_ReleaseSCache(scp);
3398         cm_ReleaseUser(userp);
3399         return code;
3400 }       
3401
3402 /* verify that this is a valid path to a directory.  I don't know why they
3403  * don't use the get file attributes call.
3404  */
3405 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3406 {
3407         char *pathp;
3408         long code = 0;
3409         cm_scache_t *rootScp;
3410         cm_scache_t *newScp;
3411         cm_user_t *userp;
3412         unsigned int attrs;
3413         int caseFold;
3414         char *tidPathp;
3415         cm_req_t req;
3416
3417         cm_InitReq(&req);
3418
3419         pathp = smb_GetSMBData(inp, NULL);
3420         pathp = smb_ParseASCIIBlock(pathp, NULL);
3421         osi_Log1(smb_logp, "SMB receive check path %s",
3422                           osi_LogSaveString(smb_logp, pathp));
3423
3424         if (!pathp) {
3425                 return CM_ERROR_BADFD;
3426         }
3427         
3428         rootScp = cm_rootSCachep;
3429         
3430         userp = smb_GetUser(vcp, inp);
3431
3432         caseFold = CM_FLAG_CASEFOLD;
3433
3434         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3435         code = cm_NameI(rootScp, pathp,
3436                                          caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3437                                          userp, tidPathp, &req, &newScp);
3438
3439         if (code) {
3440                 cm_ReleaseUser(userp);
3441                 return code;
3442         }
3443         
3444         /* now lock the vnode with a callback; returns with newScp locked */
3445         lock_ObtainMutex(&newScp->mx);
3446         code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3447                                           CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3448         if (code && code != CM_ERROR_NOACCESS) {
3449                 lock_ReleaseMutex(&newScp->mx);
3450                 cm_ReleaseSCache(newScp);
3451                 cm_ReleaseUser(userp);
3452                 return code;
3453         }
3454
3455         attrs = smb_Attributes(newScp);
3456
3457         if (!(attrs & 0x10))
3458                 code = CM_ERROR_NOTDIR;
3459
3460         lock_ReleaseMutex(&newScp->mx);
3461
3462         cm_ReleaseSCache(newScp);
3463         cm_ReleaseUser(userp);
3464         return code;
3465 }       
3466
3467 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3468 {
3469         char *pathp;
3470         long code = 0;
3471         cm_scache_t *rootScp;
3472         unsigned short attribute;
3473         cm_attr_t attr;
3474         cm_scache_t *newScp;
3475         long dosTime;
3476         cm_user_t *userp;
3477         int caseFold;
3478         char *tidPathp;
3479         cm_req_t req;
3480
3481         cm_InitReq(&req);
3482
3483         /* decode basic attributes we're passed */
3484         attribute = smb_GetSMBParm(inp, 0);
3485         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3486
3487         pathp = smb_GetSMBData(inp, NULL);
3488         pathp = smb_ParseASCIIBlock(pathp, NULL);
3489         
3490         if (!pathp) {
3491                 return CM_ERROR_BADSMB;
3492         }
3493         
3494         osi_Log2(smb_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3495                          dosTime, attribute);
3496
3497         rootScp = cm_rootSCachep;
3498         
3499         userp = smb_GetUser(vcp, inp);
3500
3501         caseFold = CM_FLAG_CASEFOLD;
3502
3503         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3504         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3505                                         tidPathp, &req, &newScp);
3506
3507         if (code) {
3508                 cm_ReleaseUser(userp);
3509                 return code;
3510         }
3511         
3512         /* now lock the vnode with a callback; returns with newScp locked; we
3513          * need the current status to determine what the new status is, in some
3514          * cases.
3515          */
3516         lock_ObtainMutex(&newScp->mx);
3517         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3518                                          CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3519         if (code) {
3520                 lock_ReleaseMutex(&newScp->mx);
3521                 cm_ReleaseSCache(newScp);
3522                 cm_ReleaseUser(userp);
3523                 return code;
3524         }
3525
3526         /* Check for RO volume */
3527         if (newScp->flags & CM_SCACHEFLAG_RO) {
3528                 lock_ReleaseMutex(&newScp->mx);
3529                 cm_ReleaseSCache(newScp);
3530                 cm_ReleaseUser(userp);
3531                 return CM_ERROR_READONLY;
3532         }
3533
3534         /* prepare for setattr call */
3535         attr.mask = 0;
3536         if (dosTime != 0) {
3537                 attr.mask |= CM_ATTRMASK_CLIENTMODTIME;
3538                 smb_UnixTimeFromDosUTime(&attr.clientModTime, dosTime);
3539         }
3540         if ((newScp->unixModeBits & 0222) && (attribute & 1) != 0) {
3541                 /* we're told to make a writable file read-only */
3542                 attr.unixModeBits = newScp->unixModeBits & ~0222;
3543                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3544         }
3545         else if ((newScp->unixModeBits & 0222) == 0 && (attribute & 1) == 0) {
3546                 /* we're told to make a read-only file writable */
3547                 attr.unixModeBits = newScp->unixModeBits | 0222;
3548                 attr.mask |= CM_ATTRMASK_UNIXMODEBITS;
3549         }
3550         lock_ReleaseMutex(&newScp->mx);
3551
3552         /* now call setattr */
3553         if (attr.mask)
3554                 code = cm_SetAttr(newScp, &attr, userp, &req);
3555         else
3556                 code = 0;
3557         
3558         cm_ReleaseSCache(newScp);
3559         cm_ReleaseUser(userp);
3560
3561         return code;
3562 }
3563
3564 long smb_ReceiveCoreGetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3565 {
3566         char *pathp;
3567         long code = 0;
3568         cm_scache_t *rootScp;
3569         cm_scache_t *newScp, *dscp;
3570         long dosTime;
3571         int attrs;
3572         cm_user_t *userp;
3573         int caseFold;
3574         char *tidPathp;
3575         cm_space_t *spacep;
3576         char *lastComp;
3577         cm_req_t req;
3578
3579         cm_InitReq(&req);
3580
3581         pathp = smb_GetSMBData(inp, NULL);
3582         pathp = smb_ParseASCIIBlock(pathp, NULL);
3583         
3584         if (!pathp) {
3585                 return CM_ERROR_BADSMB;
3586         }
3587         
3588         if (*pathp == 0)                /* null path */
3589                 pathp = "\\";
3590
3591         osi_Log1(smb_logp, "SMB receive getfile attributes path %s",
3592                          osi_LogSaveString(smb_logp, pathp));
3593
3594         rootScp = cm_rootSCachep;
3595         
3596         userp = smb_GetUser(vcp, inp);
3597
3598         /* we shouldn't need this for V3 requests, but we seem to */
3599         caseFold = CM_FLAG_CASEFOLD;
3600
3601         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3602
3603         /*
3604          * XXX Strange hack XXX
3605          *
3606          * As of Patch 5 (16 July 97), we are having the following problem:
3607          * In NT Explorer 4.0, whenever we click on a directory, AFS gets
3608          * requests to look up "desktop.ini" in all the subdirectories.
3609          * This can cause zillions of timeouts looking up non-existent cells
3610          * and volumes, especially in the top-level directory.
3611          *
3612          * We have not found any way to avoid this or work around it except
3613          * to explicitly ignore the requests for mount points that haven't
3614          * yet been evaluated and for directories that haven't yet been
3615          * fetched.
3616          *
3617          * We should modify this hack to provide a fake desktop.ini file
3618          * http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/programmersguide/shell_basics/shell_basics_extending/custom.asp
3619          */
3620         spacep = inp->spacep;
3621         smb_StripLastComponent(spacep->data, &lastComp, pathp);
3622         if (lastComp && stricmp(lastComp, "\\desktop.ini") == 0) {
3623                 code = cm_NameI(rootScp, spacep->data,
3624                                                 caseFold | CM_FLAG_DIRSEARCH | CM_FLAG_FOLLOW,
3625                                                 userp, tidPathp, &req, &dscp);
3626                 if (code == 0) {
3627                         if (dscp->fileType == CM_SCACHETYPE_MOUNTPOINT
3628                             && !dscp->mountRootFidp)
3629                                 code = CM_ERROR_NOSUCHFILE;
3630                         else if (dscp->fileType == CM_SCACHETYPE_DIRECTORY) {
3631                                 cm_buf_t *bp = buf_Find(dscp, &hzero);
3632                                 if (bp)
3633                                         buf_Release(bp);
3634                                 else
3635                                         code = CM_ERROR_NOSUCHFILE;
3636                         }
3637                         cm_ReleaseSCache(dscp);
3638                         if (code) {
3639                                 cm_ReleaseUser(userp);
3640                                 return code;
3641                         }
3642                 }
3643         }
3644
3645         code = cm_NameI(rootScp, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3646                                         tidPathp, &req, &newScp);
3647
3648         if (code) {
3649                 cm_ReleaseUser(userp);
3650                 return code;
3651         }
3652         
3653         /* now lock the vnode with a callback; returns with newScp locked */
3654         lock_ObtainMutex(&newScp->mx);
3655         code = cm_SyncOp(newScp, NULL, userp, &req, 0,
3656                                          CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3657         if (code) {
3658                 lock_ReleaseMutex(&newScp->mx);
3659                 cm_ReleaseSCache(newScp);
3660                 cm_ReleaseUser(userp);
3661                 return code;
3662         }
3663
3664 #ifdef undef
3665     /* use smb_Attributes instead.   Also the fact that a file is 
3666          * in a readonly volume doesn't mean it shojuld be marked as RO 
3667          */
3668         if (newScp->fileType == CM_SCACHETYPE_DIRECTORY
3669                 || newScp->fileType == CM_SCACHETYPE_MOUNTPOINT)
3670                 attrs = SMB_ATTR_DIRECTORY;
3671         else
3672                 attrs = 0;
3673         if ((newScp->unixModeBits & 0222) == 0 || (newScp->flags & CM_SCACHEFLAG_RO))
3674                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
3675 #else
3676     attrs = smb_Attributes(newScp);
3677 #endif
3678
3679         smb_SetSMBParm(outp, 0, attrs);
3680         
3681         smb_DosUTimeFromUnixTime(&dosTime, newScp->clientModTime);
3682         smb_SetSMBParm(outp, 1, dosTime & 0xffff);
3683         smb_SetSMBParm(outp, 2, (dosTime>>16) & 0xffff);
3684         smb_SetSMBParm(outp, 3, newScp->length.LowPart & 0xffff);
3685         smb_SetSMBParm(outp, 4, (newScp->length.LowPart >> 16) & 0xffff);
3686         smb_SetSMBParm(outp, 5, 0);
3687         smb_SetSMBParm(outp, 6, 0);
3688         smb_SetSMBParm(outp, 7, 0);
3689         smb_SetSMBParm(outp, 8, 0);
3690         smb_SetSMBParm(outp, 9, 0);
3691         smb_SetSMBDataLength(outp, 0);
3692         lock_ReleaseMutex(&newScp->mx);
3693
3694         cm_ReleaseSCache(newScp);
3695         cm_ReleaseUser(userp);
3696         
3697         return 0;
3698 }       
3699
3700 long smb_ReceiveCoreTreeDisconnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3701 {
3702         smb_tid_t *tidp;
3703         
3704         osi_Log0(smb_logp, "SMB receive tree disconnect");
3705
3706         /* find the tree and free it */
3707         tidp = smb_FindTID(vcp, ((smb_t *)inp)->tid, 0);
3708         if (tidp) {
3709                 lock_ObtainMutex(&tidp->mx);
3710                 tidp->flags |= SMB_TIDFLAG_DELETE;
3711                 lock_ReleaseMutex(&tidp->mx);
3712                 smb_ReleaseTID(tidp);
3713         }
3714
3715         return 0;
3716 }
3717
3718 long smb_ReceiveCoreOpen(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3719 {
3720         smb_fid_t *fidp;
3721     char *pathp;
3722         char *lastNamep;
3723     int share;
3724     int attribute;
3725         long code = 0;
3726     cm_user_t *userp;
3727     cm_scache_t *scp;
3728     long dosTime;
3729     int caseFold;
3730         cm_space_t *spacep;
3731         char *tidPathp;
3732         cm_req_t req;
3733
3734         cm_InitReq(&req);
3735
3736     pathp = smb_GetSMBData(inp, NULL);
3737     pathp = smb_ParseASCIIBlock(pathp, NULL);
3738         
3739     osi_Log1(smb_logp, "SMB receive open file [%s]", osi_LogSaveString(smb_logp, pathp));
3740
3741 #ifdef DEBUG_VERBOSE
3742     {
3743         char *hexpath;
3744
3745         hexpath = osi_HexifyString( pathp );
3746         DEBUG_EVENT2("AFS", "CoreOpen H[%s] A[%s]", hexpath, pathp);
3747         free(hexpath);
3748     }
3749 #endif
3750
3751         share = smb_GetSMBParm(inp, 0);
3752     attribute = smb_GetSMBParm(inp, 1);
3753
3754         spacep = inp->spacep;
3755         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3756         if (lastNamep && strcmp(lastNamep, SMB_IOCTL_FILENAME) == 0) {
3757                 /* special case magic file name for receiving IOCTL requests
3758          * (since IOCTL calls themselves aren't getting through).
3759          */
3760         fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3761                 smb_SetupIoctlFid(fidp, spacep);
3762                 smb_SetSMBParm(outp, 0, fidp->fid);
3763         smb_SetSMBParm(outp, 1, 0);     /* attrs */
3764         smb_SetSMBParm(outp, 2, 0);     /* next 2 are DOS time */
3765         smb_SetSMBParm(outp, 3, 0);
3766         smb_SetSMBParm(outp, 4, 0);     /* next 2 are length */
3767         smb_SetSMBParm(outp, 5, 0x7fff);
3768                 /* pass the open mode back */
3769         smb_SetSMBParm(outp, 6, (share & 0xf));
3770         smb_SetSMBDataLength(outp, 0);
3771         smb_ReleaseFID(fidp);
3772         return 0;
3773     }
3774
3775         userp = smb_GetUser(vcp, inp);
3776
3777         caseFold = CM_FLAG_CASEFOLD;
3778
3779         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3780     code = cm_NameI(cm_rootSCachep, pathp, caseFold | CM_FLAG_FOLLOW, userp,
3781                     tidPathp, &req, &scp);
3782         
3783     if (code) {
3784         cm_ReleaseUser(userp);
3785                 return code;
3786         }
3787         
3788     code = cm_CheckOpen(scp, share & 0x7, 0, userp, &req);
3789         if (code) {
3790                 cm_ReleaseSCache(scp);
3791                 cm_ReleaseUser(userp);
3792                 return code;
3793         }
3794
3795         /* don't need callback to check file type, since file types never
3796          * change, and namei and cm_Lookup all stat the object at least once on
3797          * a successful return.
3798      */
3799     if (scp->fileType != CM_SCACHETYPE_FILE) {
3800                 cm_ReleaseSCache(scp);
3801         cm_ReleaseUser(userp);
3802         return CM_ERROR_ISDIR;
3803     }
3804
3805     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
3806     osi_assert(fidp);
3807
3808         /* save a pointer to the vnode */
3809     fidp->scp = scp;
3810
3811     if ((share & 0xf) == 0)
3812         fidp->flags |= SMB_FID_OPENREAD;
3813         else if ((share & 0xf) == 1)
3814         fidp->flags |= SMB_FID_OPENWRITE;
3815         else 
3816         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
3817
3818         lock_ObtainMutex(&scp->mx);
3819         smb_SetSMBParm(outp, 0, fidp->fid);
3820     smb_SetSMBParm(outp, 1, smb_Attributes(scp));
3821         smb_DosUTimeFromUnixTime(&dosTime, scp->clientModTime);
3822     smb_SetSMBParm(outp, 2, dosTime & 0xffff);
3823     smb_SetSMBParm(outp, 3, (dosTime >> 16) & 0xffff);
3824     smb_SetSMBParm(outp, 4, scp->length.LowPart & 0xffff);
3825     smb_SetSMBParm(outp, 5, (scp->length.LowPart >> 16) & 0xffff);
3826         /* pass the open mode back; XXXX add access checks */
3827     smb_SetSMBParm(outp, 6, (share & 0xf));
3828     smb_SetSMBDataLength(outp, 0);
3829         lock_ReleaseMutex(&scp->mx);
3830         
3831         /* notify open */
3832     cm_Open(scp, 0, userp);
3833
3834         /* send and free packet */
3835     smb_ReleaseFID(fidp);
3836     cm_ReleaseUser(userp);
3837     /* don't release scp, since we've squirreled away the pointer in the fid struct */
3838     return 0;
3839 }
3840
3841 typedef struct smb_unlinkRock {
3842         cm_scache_t *dscp;
3843         cm_user_t *userp;
3844         cm_req_t *reqp;
3845         smb_vc_t *vcp;
3846         char *maskp;            /* pointer to the star pattern */
3847         int hasTilde;
3848         int any;
3849 } smb_unlinkRock_t;
3850
3851 int smb_UnlinkProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3852 {
3853         long code = 0;
3854         smb_unlinkRock_t *rockp;
3855         int caseFold;
3856         int match;
3857         char shortName[13];
3858         char *matchName;
3859         
3860         rockp = vrockp;
3861
3862         if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3863                 caseFold = CM_FLAG_CASEFOLD;
3864         else 
3865                 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3866
3867         matchName = dep->name;
3868         match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3869         if (!match
3870             && rockp->hasTilde
3871             && !cm_Is8Dot3(dep->name)) {
3872                 cm_Gen8Dot3Name(dep, shortName, NULL);
3873                 matchName = shortName;
3874                 match = smb_V3MatchMask(matchName, rockp->maskp, caseFold);
3875         }
3876         if (match) {
3877                 osi_Log1(smb_logp, "Unlinking %s",
3878                                  osi_LogSaveString(smb_logp, matchName));
3879                 code = cm_Unlink(dscp, dep->name, rockp->userp, rockp->reqp);
3880                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
3881                         smb_NotifyChange(FILE_ACTION_REMOVED,
3882                                                          FILE_NOTIFY_CHANGE_FILE_NAME,
3883                                                          dscp, dep->name, NULL, TRUE);
3884                 if (code == 0)
3885                         rockp->any = 1;
3886         }
3887         else code = 0;
3888
3889         return code;
3890 }
3891
3892 long smb_ReceiveCoreUnlink(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3893 {
3894         int attribute;
3895         long code = 0;
3896         char *pathp;
3897         char *tp;
3898         cm_space_t *spacep;
3899         cm_scache_t *dscp;
3900         char *lastNamep;
3901         smb_unlinkRock_t rock;
3902         cm_user_t *userp;
3903         osi_hyper_t thyper;
3904         int caseFold;
3905         char *tidPathp;
3906         cm_req_t req;
3907
3908         cm_InitReq(&req);
3909
3910         attribute = smb_GetSMBParm(inp, 0);
3911         
3912         tp = smb_GetSMBData(inp, NULL);
3913         pathp = smb_ParseASCIIBlock(tp, &tp);
3914
3915         osi_Log1(smb_logp, "SMB receive unlink %s",
3916                          osi_LogSaveString(smb_logp, pathp));
3917
3918         spacep = inp->spacep;
3919         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
3920
3921         userp = smb_GetUser(vcp, inp);
3922
3923         caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
3924
3925         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3926         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold, userp, tidPathp,
3927                                         &req, &dscp);
3928
3929         if (code) {
3930                 cm_ReleaseUser(userp);
3931                 return code;
3932         }
3933         
3934         /* otherwise, scp points to the parent directory. */
3935         if (!lastNamep) 
3936                 lastNamep = pathp;
3937         else 
3938                 lastNamep++;
3939
3940         rock.any = 0;
3941         rock.maskp = smb_FindMask(pathp);
3942         rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
3943         
3944         thyper.LowPart = 0;
3945         thyper.HighPart = 0;
3946         rock.userp = userp;
3947         rock.reqp = &req;
3948         rock.dscp = dscp;
3949         rock.vcp = vcp;
3950         code = cm_ApplyDir(dscp, smb_UnlinkProc, &rock, &thyper, userp, &req, NULL);
3951
3952         cm_ReleaseUser(userp);
3953         
3954         cm_ReleaseSCache(dscp);
3955
3956         if (code == 0 && !rock.any)
3957                 code = CM_ERROR_NOSUCHFILE;
3958         return code;
3959 }
3960
3961 typedef struct smb_renameRock {
3962         cm_scache_t *odscp;     /* old dir */
3963         cm_scache_t *ndscp;     /* new dir */
3964         cm_user_t *userp;       /* user */
3965         cm_req_t *reqp;         /* request struct */
3966         smb_vc_t *vcp;          /* virtual circuit */
3967         char *maskp;            /* pointer to star pattern of old file name */
3968         int hasTilde;           /* star pattern might be shortname? */
3969         char *newNamep;         /* ptr to the new file's name */
3970 } smb_renameRock_t;
3971
3972 int smb_RenameProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
3973 {
3974         long code = 0;
3975         smb_renameRock_t *rockp;
3976         int caseFold;
3977         int match;
3978         char shortName[13];
3979         
3980         rockp = (smb_renameRock_t *) vrockp;
3981
3982         if (rockp->vcp->flags & SMB_VCFLAG_USEV3)
3983                 caseFold = CM_FLAG_CASEFOLD;
3984         else 
3985                 caseFold = CM_FLAG_CASEFOLD | CM_FLAG_8DOT3;
3986
3987         match = smb_V3MatchMask(dep->name, rockp->maskp, caseFold);
3988         if (!match
3989             && rockp->hasTilde
3990             && !cm_Is8Dot3(dep->name)) {
3991                 cm_Gen8Dot3Name(dep, shortName, NULL);
3992                 match = smb_V3MatchMask(shortName, rockp->maskp, caseFold);
3993         }
3994         if (match) {
3995                 code = cm_Rename(rockp->odscp, dep->name,
3996                                                  rockp->ndscp, rockp->newNamep, rockp->userp,
3997                                                  rockp->reqp);  
3998                 /* if the call worked, stop doing the search now, since we
3999                  * really only want to rename one file.
4000                  */
4001                 if (code == 0) 
4002                         code = CM_ERROR_STOPNOW;
4003         }
4004         else code = 0;
4005
4006         return code;
4007 }
4008
4009 long smb_ReceiveCoreRename(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4010 {
4011         long code = 0;
4012         char *oldPathp;
4013         char *newPathp;
4014         char *tp;
4015         cm_space_t *spacep;
4016         smb_renameRock_t rock;
4017         cm_scache_t *oldDscp;
4018         cm_scache_t *newDscp;
4019         cm_scache_t *tmpscp;
4020         char *oldLastNamep;
4021         char *newLastNamep;
4022         osi_hyper_t thyper;
4023         cm_user_t *userp;
4024         int caseFold;
4025         char *tidPathp;
4026         DWORD filter;
4027         cm_req_t req;
4028
4029         cm_InitReq(&req);
4030         
4031         tp = smb_GetSMBData(inp, NULL);
4032         oldPathp = smb_ParseASCIIBlock(tp, &tp);
4033         newPathp = smb_ParseASCIIBlock(tp, &tp);
4034
4035         osi_Log2(smb_logp, "smb rename %s to %s",
4036                          osi_LogSaveString(smb_logp, oldPathp),
4037                          osi_LogSaveString(smb_logp, newPathp));
4038
4039         spacep = inp->spacep;
4040         smb_StripLastComponent(spacep->data, &oldLastNamep, oldPathp);
4041
4042         userp = smb_GetUser(vcp, inp);
4043
4044  /*
4045   * Changed to use CASEFOLD always.  This enables us to rename Foo/baz when
4046   * what actually exists is foo/baz.  I don't know why the code used to be
4047   * the way it was.  1/29/96
4048   *
4049   *             caseFold = ((vcp->flags & SMB_VCFLAG_USEV3) ? 0: CM_FLAG_CASEFOLD);
4050   *
4051   * Changed to use CM_FLAG_FOLLOW.  7/24/96
4052   *
4053   *     caseFold = CM_FLAG_CASEFOLD;
4054   */
4055         caseFold = CM_FLAG_FOLLOW | CM_FLAG_CASEFOLD;
4056
4057         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4058         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4059                                         userp, tidPathp, &req, &oldDscp);
4060
4061         if (code) {
4062                 cm_ReleaseUser(userp);
4063                 return code;
4064         }
4065         
4066         smb_StripLastComponent(spacep->data, &newLastNamep, newPathp);
4067         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold,
4068                                         userp, tidPathp, &req, &newDscp);
4069
4070         if (code) {
4071                 cm_ReleaseSCache(oldDscp);
4072                 cm_ReleaseUser(userp);
4073                 return code;
4074         }
4075         
4076         /* otherwise, oldDscp and newDscp point to the corresponding directories.
4077          * next, get the component names, and lower case them.
4078          */
4079
4080         /* handle the old name first */
4081         if (!oldLastNamep) 
4082                 oldLastNamep = oldPathp;
4083         else 
4084                 oldLastNamep++;
4085
4086         /* and handle the new name, too */
4087         if (!newLastNamep) 
4088                 newLastNamep = newPathp;
4089         else 
4090                 newLastNamep++;
4091         
4092         /* do the vnode call */
4093         rock.odscp = oldDscp;
4094         rock.ndscp = newDscp;
4095         rock.userp = userp;
4096         rock.reqp = &req;
4097         rock.vcp = vcp;
4098         rock.maskp = oldLastNamep;
4099         rock.hasTilde = ((strchr(oldLastNamep, '~') != NULL) ? 1 : 0);
4100         rock.newNamep = newLastNamep;
4101
4102     /* Check if the file already exists; if so return error */
4103         code = cm_Lookup(newDscp,newLastNamep,CM_FLAG_CHECKPATH,userp,&req,&tmpscp);
4104         if((code != CM_ERROR_NOSUCHFILE) && (code != CM_ERROR_NOSUCHPATH) && (code != CM_ERROR_NOSUCHVOLUME) ) {
4105         cm_ReleaseSCache(newDscp);
4106         cm_ReleaseSCache(oldDscp);
4107         cm_ReleaseUser(userp);
4108         if (!code)
4109             cm_ReleaseSCache(tmpscp);
4110         /* Check if the old and the new names differ only in case. If so return
4111          * success, else return CM_ERROR_EXISTS 
4112          */
4113         if(oldDscp == newDscp && !stricmp(oldLastNamep, newLastNamep)) {
4114             osi_Log0(afsd_logp, "Rename: Old and new names are the same");
4115             code = 0;
4116         } else {
4117             /* file exist, do not rename, also fixes move */
4118             osi_Log0(afsd_logp, "Can't rename.  Target already exists");
4119             code = CM_ERROR_EXISTS;
4120         }
4121             return code; 
4122         }
4123
4124     /* Now search the directory for the pattern, and do the appropriate rename when found */
4125         thyper.LowPart = 0;             /* search dir from here */
4126     thyper.HighPart = 0;
4127
4128     code = cm_ApplyDir(oldDscp, smb_RenameProc, &rock, &thyper, userp, &req, NULL);
4129
4130     if (code == CM_ERROR_STOPNOW)
4131                 code = 0;
4132         else if (code == 0)
4133                 code = CM_ERROR_NOSUCHFILE;
4134
4135         /* Handle Change Notification */
4136         /*
4137          * Being lazy, not distinguishing between files and dirs in this
4138          * filter, since we'd have to do a lookup.
4139          */
4140         filter = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME;
4141         if (oldDscp == newDscp) {
4142                 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4143                         smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4144                                                          filter, oldDscp, oldLastNamep,
4145                                                          newLastNamep, TRUE);
4146         } else {
4147                 if (oldDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4148                         smb_NotifyChange(FILE_ACTION_RENAMED_OLD_NAME,
4149                                                          filter, oldDscp, oldLastNamep,
4150                                                          NULL, TRUE);
4151                 if (newDscp->flags & CM_SCACHEFLAG_ANYWATCH)
4152                         smb_NotifyChange(FILE_ACTION_RENAMED_NEW_NAME,
4153                                                          filter, newDscp, newLastNamep,
4154                                                          NULL, TRUE);
4155         }
4156
4157         cm_ReleaseUser(userp);
4158         cm_ReleaseSCache(oldDscp);
4159         cm_ReleaseSCache(newDscp);
4160         return code;
4161 }
4162
4163 typedef struct smb_rmdirRock {
4164         cm_scache_t *dscp;
4165         cm_user_t *userp;
4166         cm_req_t *reqp;
4167         char *maskp;            /* pointer to the star pattern */
4168         int hasTilde;
4169         int any;
4170 } smb_rmdirRock_t;
4171
4172 int smb_RmdirProc(cm_scache_t *dscp, cm_dirEntry_t *dep, void *vrockp, osi_hyper_t *offp)
4173 {
4174         long code = 0;
4175         smb_rmdirRock_t *rockp;
4176         int match;
4177         char shortName[13];
4178         char *matchName;
4179         
4180         rockp = vrockp;
4181
4182         matchName = dep->name;
4183         match = (cm_stricmp(matchName, rockp->maskp) == 0);
4184         if (!match
4185             && rockp->hasTilde
4186             && !cm_Is8Dot3(dep->name)) {
4187                 cm_Gen8Dot3Name(dep, shortName, NULL);
4188                 matchName = shortName;
4189                 match = (cm_stricmp(matchName, rockp->maskp) == 0);
4190         }
4191         if (match) {
4192                 osi_Log1(smb_logp, "Removing directory %s",
4193                                  osi_LogSaveString(smb_logp, matchName));
4194                 code = cm_RemoveDir(dscp, dep->name, rockp->userp, rockp->reqp);
4195                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4196                         smb_NotifyChange(FILE_ACTION_REMOVED,
4197                                                          FILE_NOTIFY_CHANGE_DIR_NAME,
4198                                                          dscp, dep->name, NULL, TRUE);
4199                 if (code == 0)
4200                         rockp->any = 1;
4201         }
4202         else code = 0;
4203
4204         return code;
4205 }
4206
4207 long smb_ReceiveCoreRemoveDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4208 {
4209         long code = 0;
4210         char *pathp;
4211         char *tp;
4212         cm_space_t *spacep;
4213         cm_scache_t *dscp;
4214         char *lastNamep;
4215         smb_rmdirRock_t rock;
4216         cm_user_t *userp;
4217         osi_hyper_t thyper;
4218         int caseFold;
4219         char *tidPathp;
4220         cm_req_t req;
4221
4222         cm_InitReq(&req);
4223
4224         tp = smb_GetSMBData(inp, NULL);
4225         pathp = smb_ParseASCIIBlock(tp, &tp);
4226
4227         spacep = inp->spacep;
4228         smb_StripLastComponent(spacep->data, &lastNamep, pathp);
4229
4230         userp = smb_GetUser(vcp, inp);
4231
4232         caseFold = CM_FLAG_CASEFOLD;
4233
4234         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
4235         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
4236                                         userp, tidPathp, &req, &dscp);
4237
4238         if (code) {
4239                 cm_ReleaseUser(userp);
4240                 return code;
4241         }
4242         
4243         /* otherwise, scp points to the parent directory. */
4244         if (!lastNamep) 
4245                 lastNamep = pathp;
4246         else 
4247                 lastNamep++;
4248         
4249         rock.any = 0;
4250         rock.maskp = lastNamep;
4251         rock.hasTilde = ((strchr(rock.maskp, '~') != NULL) ? 1 : 0);
4252
4253         thyper.LowPart = 0;
4254         thyper.HighPart = 0;
4255         rock.userp = userp;
4256         rock.reqp = &req;
4257         rock.dscp = dscp;
4258         code = cm_ApplyDir(dscp, smb_RmdirProc, &rock, &thyper, userp, &req, NULL);
4259
4260         cm_ReleaseUser(userp);
4261         
4262         cm_ReleaseSCache(dscp);
4263
4264         if (code == 0 && !rock.any)
4265                 code = CM_ERROR_NOSUCHFILE;        
4266         return code;
4267 }
4268
4269 long smb_ReceiveCoreFlush(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4270 {
4271         unsigned short fid;
4272     smb_fid_t *fidp;
4273     cm_user_t *userp;
4274     long code = 0;
4275     cm_req_t req;
4276
4277         cm_InitReq(&req);
4278
4279         fid = smb_GetSMBParm(inp, 0);
4280         
4281         osi_Log1(smb_logp, "SMB flush fid %d", fid);
4282
4283         fid = smb_ChainFID(fid, inp);
4284     fidp = smb_FindFID(vcp, fid, 0);
4285     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
4286         if (fidp)
4287             smb_ReleaseFID(fidp);
4288         return CM_ERROR_BADFD;
4289     }
4290         
4291     userp = smb_GetUser(vcp, inp);
4292
4293     lock_ObtainMutex(&fidp->mx);
4294     if (fidp->flags & SMB_FID_OPENWRITE)
4295         code = cm_FSync(fidp->scp, userp, &req);
4296         else 
4297                 code = 0;
4298     lock_ReleaseMutex(&fidp->mx);
4299         
4300     smb_ReleaseFID(fidp);
4301         
4302     cm_ReleaseUser(userp);
4303         
4304     return code;
4305 }
4306
4307 struct smb_FullNameRock {
4308         char *name;
4309         cm_scache_t *vnode;
4310         char *fullName;
4311 };
4312
4313 int smb_FullNameProc(cm_scache_t *scp, cm_dirEntry_t *dep, void *rockp,
4314         osi_hyper_t *offp)
4315 {
4316         char shortName[13];
4317         struct smb_FullNameRock *vrockp;
4318
4319         vrockp = rockp;
4320
4321         if (!cm_Is8Dot3(dep->name)) {
4322                 cm_Gen8Dot3Name(dep, shortName, NULL);
4323
4324                 if (strcmp(shortName, vrockp->name) == 0) {
4325                         vrockp->fullName = strdup(dep->name);
4326                         return CM_ERROR_STOPNOW;
4327                 }
4328         }
4329         if (stricmp(dep->name, vrockp->name) == 0
4330             && ntohl(dep->fid.vnode) == vrockp->vnode->fid.vnode
4331             && ntohl(dep->fid.unique) == vrockp->vnode->fid.unique) {
4332                 vrockp->fullName = strdup(dep->name);
4333                 return CM_ERROR_STOPNOW;
4334         }
4335         return 0;
4336 }
4337
4338 void smb_FullName(cm_scache_t *dscp, cm_scache_t *scp, char *pathp,
4339         char **newPathp, cm_user_t *userp, cm_req_t *reqp)
4340 {
4341         struct smb_FullNameRock rock;
4342         long code = 0;
4343
4344         rock.name = pathp;
4345         rock.vnode = scp;
4346
4347         code = cm_ApplyDir(dscp, smb_FullNameProc, &rock, NULL, 
4348                                 userp, reqp, NULL); 
4349         if (code == CM_ERROR_STOPNOW)
4350                 *newPathp = rock.fullName;
4351         else
4352                 *newPathp = strdup(pathp);
4353 }
4354
4355 long smb_ReceiveCoreClose(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4356 {
4357         unsigned short fid;
4358     smb_fid_t *fidp;
4359     cm_user_t *userp;
4360         long dosTime;
4361     long code = 0;
4362         cm_req_t req;
4363
4364         cm_InitReq(&req);
4365
4366         fid = smb_GetSMBParm(inp, 0);
4367         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
4368         
4369         osi_Log1(smb_logp, "SMB close fid %d", fid);
4370
4371         fid = smb_ChainFID(fid, inp);
4372     fidp = smb_FindFID(vcp, fid, 0);
4373     if (!fidp) {
4374         return CM_ERROR_BADFD;
4375     }
4376         
4377         userp = smb_GetUser(vcp, inp);
4378
4379     lock_ObtainMutex(&fidp->mx);
4380
4381         /* Don't jump the gun on an async raw write */
4382         while (fidp->raw_writers) {
4383                 lock_ReleaseMutex(&fidp->mx);
4384                 thrd_WaitForSingleObject_Event(fidp->raw_write_event, RAWTIMEOUT);
4385                 lock_ObtainMutex(&fidp->mx);
4386         }
4387
4388         fidp->flags |= SMB_FID_DELETE;
4389         
4390         /* watch for ioctl closes, and read-only opens */
4391     if (fidp->scp != NULL
4392         && (fidp->flags & (SMB_FID_OPENWRITE | SMB_FID_DELONCLOSE))
4393          == SMB_FID_OPENWRITE) {
4394                 if (dosTime != 0 && dosTime != -1) {
4395                         fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4396             /* This fixes defect 10958 */
4397             CompensateForSmbClientLastWriteTimeBugs(&dosTime);
4398                         smb_UnixTimeFromDosUTime(&fidp->scp->clientModTime, dosTime);
4399                 }
4400         code = cm_FSync(fidp->scp, userp, &req);
4401         }
4402         else 
4403         code = 0;
4404
4405         if (fidp->flags & SMB_FID_DELONCLOSE) {
4406                 cm_scache_t *dscp = fidp->NTopen_dscp;
4407                 char *pathp = fidp->NTopen_pathp;
4408                 char *fullPathp;
4409
4410                 smb_FullName(dscp, fidp->scp, pathp, &fullPathp, userp, &req);
4411                 if (fidp->scp->fileType == CM_SCACHETYPE_DIRECTORY) {
4412                         code = cm_RemoveDir(dscp, fullPathp, userp, &req);
4413                         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4414                                 smb_NotifyChange(FILE_ACTION_REMOVED,
4415                                  FILE_NOTIFY_CHANGE_DIR_NAME,
4416                                  dscp, fullPathp, NULL, TRUE);
4417                 }
4418                 else 
4419         {
4420                         code = cm_Unlink(dscp, fullPathp, userp, &req);
4421                         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
4422                                 smb_NotifyChange(FILE_ACTION_REMOVED,
4423                                  FILE_NOTIFY_CHANGE_FILE_NAME,
4424                                  dscp, fullPathp, NULL, TRUE);
4425                 }
4426                 free(fullPathp);
4427         }
4428     lock_ReleaseMutex(&fidp->mx);
4429
4430     if (fidp->flags & SMB_FID_NTOPEN) {
4431                 cm_ReleaseSCache(fidp->NTopen_dscp);
4432                 free(fidp->NTopen_pathp);
4433         }
4434         if (fidp->NTopen_wholepathp)
4435                 free(fidp->NTopen_wholepathp);
4436     
4437     smb_ReleaseFID(fidp);
4438         cm_ReleaseUser(userp);
4439     return code;
4440 }
4441
4442 /*
4443  * smb_ReadData -- common code for Read, Read And X, and Raw Read
4444  */
4445 #ifndef DJGPP
4446 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4447         cm_user_t *userp, long *readp)
4448 #else /* DJGPP */
4449 long smb_ReadData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4450         cm_user_t *userp, long *readp, int dosflag)
4451 #endif /* !DJGPP */
4452 {
4453         osi_hyper_t offset;
4454         long code = 0;
4455         cm_scache_t *scp;
4456         cm_buf_t *bufferp;
4457         osi_hyper_t fileLength;
4458         osi_hyper_t thyper;
4459         osi_hyper_t lastByte;
4460         osi_hyper_t bufferOffset;
4461         long bufIndex, nbytes;
4462         int chunk;
4463         int sequential = 0;
4464         cm_req_t req;
4465
4466         cm_InitReq(&req);
4467
4468         bufferp = NULL;
4469         offset = *offsetp;
4470
4471         lock_ObtainMutex(&fidp->mx);
4472         scp = fidp->scp;
4473         lock_ObtainMutex(&scp->mx);
4474
4475         if (offset.HighPart == 0) {
4476                 chunk = offset.LowPart >> cm_logChunkSize;
4477                 if (chunk != fidp->curr_chunk) {
4478                         fidp->prev_chunk = fidp->curr_chunk;
4479                         fidp->curr_chunk = chunk;
4480                 }
4481                 if (fidp->curr_chunk == fidp->prev_chunk + 1)
4482                         sequential = 1;
4483         }
4484
4485         /* start by looking up the file's end */
4486         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4487                                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
4488         if (code) goto done;
4489
4490         /* now we have the entry locked, look up the length */
4491         fileLength = scp->length;
4492
4493         /* adjust count down so that it won't go past EOF */
4494         thyper.LowPart = count;
4495         thyper.HighPart = 0;
4496         thyper = LargeIntegerAdd(offset, thyper);       /* where read should end */
4497         lastByte = thyper;
4498         if (LargeIntegerGreaterThan(thyper, fileLength)) {
4499                 /* we'd read past EOF, so just stop at fileLength bytes.
4500                  * Start by computing how many bytes remain in the file.
4501                  */
4502                 thyper = LargeIntegerSubtract(fileLength, offset);
4503
4504                 /* if we are past EOF, read 0 bytes */
4505                 if (LargeIntegerLessThanZero(thyper))
4506                         count = 0;
4507                 else
4508                         count = thyper.LowPart;
4509         }
4510
4511         *readp = count;
4512
4513         /* now, copy the data one buffer at a time,
4514          * until we've filled the request packet
4515          */
4516         while (1) {
4517                 /* if we've copied all the data requested, we're done */
4518                 if (count <= 0) break;
4519                 
4520                 /* otherwise, load up a buffer of data */
4521                 thyper.HighPart = offset.HighPart;
4522                 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4523                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4524                         /* wrong buffer */
4525                         if (bufferp) {
4526                                 buf_Release(bufferp);
4527                                 bufferp = NULL;
4528                         }
4529                         lock_ReleaseMutex(&scp->mx);
4530
4531                         lock_ObtainRead(&scp->bufCreateLock);
4532                         code = buf_Get(scp, &thyper, &bufferp);
4533                         lock_ReleaseRead(&scp->bufCreateLock);
4534
4535                         lock_ObtainMutex(&scp->mx);
4536                         if (code) goto done;
4537                         bufferOffset = thyper;
4538
4539                         /* now get the data in the cache */
4540                         while (1) {
4541                                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4542                                                                   CM_SCACHESYNC_NEEDCALLBACK
4543                                                                   | CM_SCACHESYNC_READ);
4544                                 if (code) goto done;
4545                                 
4546                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
4547
4548                                 /* otherwise, load the buffer and try again */
4549                                 code = cm_GetBuffer(scp, bufferp, NULL, userp, &req);
4550                                 if (code) break;
4551                         }
4552                         if (code) {
4553                                 buf_Release(bufferp);
4554                                 bufferp = NULL;
4555                                 goto done;
4556                         }
4557                 }       /* if (wrong buffer) ... */
4558                 
4559                 /* now we have the right buffer loaded.  Copy out the
4560                  * data from here to the user's buffer.
4561                  */
4562                 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4563
4564                 /* and figure out how many bytes we want from this buffer */
4565                 nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
4566                 if (nbytes > count) nbytes = count;     /* don't go past EOF */
4567                 
4568                 /* now copy the data */
4569 #ifdef DJGPP
4570                 if (dosflag)
4571                         dosmemput(bufferp->datap + bufIndex, nbytes, (dos_ptr)op);
4572                 else
4573 #endif /* DJGPP */
4574                         memcpy(op, bufferp->datap + bufIndex, nbytes);
4575                 
4576                 /* adjust counters, pointers, etc. */
4577                 op += nbytes;
4578                 count -= nbytes;
4579                 thyper.LowPart = nbytes;
4580                 thyper.HighPart = 0;
4581                 offset = LargeIntegerAdd(thyper, offset);
4582         } /* while 1 */
4583
4584   done:
4585         lock_ReleaseMutex(&scp->mx);
4586         lock_ReleaseMutex(&fidp->mx);
4587         if (bufferp) 
4588                 buf_Release(bufferp);
4589
4590         if (code == 0 && sequential)
4591                 cm_ConsiderPrefetch(scp, &lastByte, userp, &req);
4592
4593         return code;
4594 }
4595
4596 /*
4597  * smb_WriteData -- common code for Write and Raw Write
4598  */
4599 #ifndef DJGPP
4600 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4601         cm_user_t *userp, long *writtenp)
4602 #else /* DJGPP */
4603 long smb_WriteData(smb_fid_t *fidp, osi_hyper_t *offsetp, long count, char *op,
4604         cm_user_t *userp, long *writtenp, int dosflag)
4605 #endif /* !DJGPP */
4606 {
4607         osi_hyper_t offset;
4608         long code = 0;
4609         long written = 0;
4610         cm_scache_t *scp;
4611         osi_hyper_t fileLength; /* file's length at start of write */
4612         osi_hyper_t minLength;  /* don't read past this */
4613         long nbytes;            /* # of bytes to transfer this iteration */
4614         cm_buf_t *bufferp;
4615         osi_hyper_t thyper;             /* hyper tmp variable */
4616         osi_hyper_t bufferOffset;
4617         long bufIndex;                  /* index in buffer where our data is */
4618         int doWriteBack;
4619         osi_hyper_t writeBackOffset;    /* offset of region to write back when
4620         * I/O is done */
4621         DWORD filter = 0;
4622         cm_req_t req;
4623
4624         cm_InitReq(&req);
4625
4626         bufferp = NULL;
4627         doWriteBack = 0;
4628         offset = *offsetp;
4629
4630         lock_ObtainMutex(&fidp->mx);
4631         scp = fidp->scp;
4632         lock_ObtainMutex(&scp->mx);
4633
4634         /* start by looking up the file's end */
4635         code = cm_SyncOp(scp, NULL, userp, &req, 0,
4636                                          CM_SCACHESYNC_NEEDCALLBACK
4637                                          | CM_SCACHESYNC_SETSTATUS
4638                                          | CM_SCACHESYNC_GETSTATUS);
4639         if (code) 
4640                 goto done;
4641         
4642         /* make sure we have a writable FD */
4643         if (!(fidp->flags & SMB_FID_OPENWRITE)) {
4644                 code = CM_ERROR_BADFDOP;
4645                 goto done;
4646         }
4647         
4648         /* now we have the entry locked, look up the length */
4649         fileLength = scp->length;
4650         minLength = fileLength;
4651         if (LargeIntegerGreaterThan(minLength, scp->serverLength))
4652                 minLength = scp->serverLength;
4653
4654         /* adjust file length if we extend past EOF */
4655         thyper.LowPart = count;
4656         thyper.HighPart = 0;
4657         thyper = LargeIntegerAdd(offset, thyper);       /* where write should end */
4658         if (LargeIntegerGreaterThan(thyper, fileLength)) {
4659                 /* we'd write past EOF, so extend the file */
4660                 scp->mask |= CM_SCACHEMASK_LENGTH;
4661                 scp->length = thyper;
4662                 filter |= (FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE);
4663         } else
4664                 filter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
4665         
4666         /* now, if the new position (thyper) and the old (offset) are in
4667          * different storeback windows, remember to store back the previous
4668          * storeback window when we're done with the write.
4669          */
4670         if ((thyper.LowPart & (-cm_chunkSize)) !=
4671                  (offset.LowPart & (-cm_chunkSize))) {
4672                 /* they're different */
4673                 doWriteBack = 1;
4674                 writeBackOffset.HighPart = offset.HighPart;
4675                 writeBackOffset.LowPart = offset.LowPart & (-cm_chunkSize);
4676         }
4677         
4678         *writtenp = count;
4679
4680         /* now, copy the data one buffer at a time, until we've filled the
4681          * request packet */
4682         while (1) {
4683                 /* if we've copied all the data requested, we're done */
4684                 if (count <= 0) break;
4685
4686                 /* handle over quota or out of space */
4687                 if (scp->flags & (CM_SCACHEFLAG_OVERQUOTA | CM_SCACHEFLAG_OUTOFSPACE)) {
4688                         *writtenp = written;
4689                         break;
4690                 }
4691                 
4692                 /* otherwise, load up a buffer of data */
4693                 thyper.HighPart = offset.HighPart;
4694                 thyper.LowPart = offset.LowPart & ~(buf_bufferSize-1);
4695                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
4696                         /* wrong buffer */
4697                         if (bufferp) {
4698                                 lock_ReleaseMutex(&bufferp->mx);
4699                                 buf_Release(bufferp);
4700                                 bufferp = NULL;
4701                         }       
4702                         lock_ReleaseMutex(&scp->mx);
4703
4704                         lock_ObtainRead(&scp->bufCreateLock);
4705                         code = buf_Get(scp, &thyper, &bufferp);
4706                         lock_ReleaseRead(&scp->bufCreateLock);
4707
4708                         lock_ObtainMutex(&bufferp->mx);
4709                         lock_ObtainMutex(&scp->mx);
4710                         if (code) goto done;
4711
4712                         bufferOffset = thyper;
4713
4714                         /* now get the data in the cache */
4715                         while (1) {
4716                                 code = cm_SyncOp(scp, bufferp, userp, &req, 0,
4717                                                                  CM_SCACHESYNC_NEEDCALLBACK
4718                                                                  | CM_SCACHESYNC_WRITE
4719                                                                  | CM_SCACHESYNC_BUFLOCKED);
4720                                 if (code) 
4721                                         goto done;
4722                                 
4723                                 /* If we're overwriting the entire buffer, or
4724                                  * if we're writing at or past EOF, mark the
4725                                  * buffer as current so we don't call
4726                                  * cm_GetBuffer.  This skips the fetch from the
4727                                  * server in those cases where we're going to 
4728                                  * obliterate all the data in the buffer anyway,
4729                                  * or in those cases where there is no useful
4730                                  * data at the server to start with.
4731                                  *
4732                                  * Use minLength instead of scp->length, since
4733                                  * the latter has already been updated by this
4734                                  * call.
4735                                  */
4736                                 if (LargeIntegerGreaterThanOrEqualTo(
4737                                         bufferp->offset, minLength)
4738                                     || LargeIntegerEqualTo(offset, bufferp->offset)
4739                                        && (count >= buf_bufferSize
4740                                            || LargeIntegerGreaterThanOrEqualTo(
4741                                                LargeIntegerAdd(offset,
4742                                                    ConvertLongToLargeInteger(count)),
4743                                                minLength))) {
4744                                         if (count < buf_bufferSize
4745                                             && bufferp->dataVersion == -1)
4746                                             memset(bufferp->datap, 0,
4747                                                    buf_bufferSize);
4748                                         bufferp->dataVersion = scp->dataVersion;
4749                                 }
4750
4751                                 if (cm_HaveBuffer(scp, bufferp, 1)) break;
4752
4753                                 /* otherwise, load the buffer and try again */
4754                                 lock_ReleaseMutex(&bufferp->mx);
4755                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
4756                                                                         &req);
4757                                 lock_ReleaseMutex(&scp->mx);
4758                                 lock_ObtainMutex(&bufferp->mx);
4759                                 lock_ObtainMutex(&scp->mx);
4760                                 if (code) break;
4761                         }
4762                         if (code) {
4763                                 lock_ReleaseMutex(&bufferp->mx);
4764                                 buf_Release(bufferp);
4765                                 bufferp = NULL;
4766                                 goto done;
4767                         }
4768                 }       /* if (wrong buffer) ... */
4769                 
4770                 /* now we have the right buffer loaded.  Copy out the
4771                  * data from here to the user's buffer.
4772                  */
4773                 bufIndex = offset.LowPart & (buf_bufferSize - 1);
4774
4775                 /* and figure out how many bytes we want from this buffer */
4776                 nbytes = buf_bufferSize - bufIndex;     /* what remains in buffer */
4777                 if (nbytes > count) 
4778                         nbytes = count; /* don't go past end of request */
4779                 
4780                 /* now copy the data */
4781 #ifdef DJGPP
4782                 if (dosflag)
4783                         dosmemget((dos_ptr)op, nbytes, bufferp->datap + bufIndex);
4784                 else
4785 #endif /* DJGPP */
4786                         memcpy(bufferp->datap + bufIndex, op, nbytes);
4787                 buf_SetDirty(bufferp);
4788
4789                 /* and record the last writer */
4790                 if (bufferp->userp != userp) {
4791                         cm_HoldUser(userp);
4792                         if (bufferp->userp) 
4793                 cm_ReleaseUser(bufferp->userp);
4794                         bufferp->userp = userp;
4795                 }
4796                 
4797                 /* adjust counters, pointers, etc. */
4798                 op += nbytes;
4799                 count -= nbytes;
4800                 written += nbytes;
4801                 thyper.LowPart = nbytes;
4802                 thyper.HighPart = 0;
4803                 offset = LargeIntegerAdd(thyper, offset);
4804         } /* while 1 */
4805
4806   done:
4807         lock_ReleaseMutex(&scp->mx);
4808         lock_ReleaseMutex(&fidp->mx);
4809         if (bufferp) {
4810                 lock_ReleaseMutex(&bufferp->mx);
4811                 buf_Release(bufferp);
4812         }
4813
4814         if (code == 0 && filter != 0 && (fidp->flags & SMB_FID_NTOPEN)
4815             && (fidp->NTopen_dscp->flags & CM_SCACHEFLAG_ANYWATCH)) {
4816                 smb_NotifyChange(FILE_ACTION_MODIFIED, filter,
4817                                                  fidp->NTopen_dscp, fidp->NTopen_pathp,
4818                                                  NULL, TRUE);
4819         }
4820
4821         if (code == 0 && doWriteBack) {
4822                 lock_ObtainMutex(&scp->mx);
4823                 cm_SyncOp(scp, NULL, userp, &req, 0, CM_SCACHESYNC_ASYNCSTORE);
4824                 lock_ReleaseMutex(&scp->mx);
4825                 cm_QueueBKGRequest(scp, cm_BkgStore, writeBackOffset.LowPart,
4826                                                    writeBackOffset.HighPart, cm_chunkSize, 0, userp);
4827         }
4828
4829         return code;
4830 }
4831
4832 long smb_ReceiveCoreWrite(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4833 {
4834         osi_hyper_t offset;
4835     long count, written = 0;
4836     unsigned short fd;
4837     smb_fid_t *fidp;
4838     long code = 0;
4839     cm_user_t *userp;
4840     cm_attr_t truncAttr;        /* attribute struct used for truncating file */
4841     char *op;
4842     int inDataBlockCount;
4843
4844     fd = smb_GetSMBParm(inp, 0);
4845     count = smb_GetSMBParm(inp, 1);
4846     offset.HighPart = 0;        /* too bad */
4847     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
4848
4849     op = smb_GetSMBData(inp, NULL);
4850         op = smb_ParseDataBlock(op, NULL, &inDataBlockCount);
4851
4852     osi_Log3(smb_logp, "smb_ReceiveCoreWrite fd %d, off 0x%x, size 0x%x",
4853              fd, offset.LowPart, count);
4854         
4855         fd = smb_ChainFID(fd, inp);
4856     fidp = smb_FindFID(vcp, fd, 0);
4857     if (!fidp) {
4858                 return CM_ERROR_BADFD;
4859     }
4860         
4861     if (fidp->flags & SMB_FID_IOCTL)
4862         return smb_IoctlWrite(fidp, vcp, inp, outp);
4863         
4864         userp = smb_GetUser(vcp, inp);
4865
4866         /* special case: 0 bytes transferred means truncate to this position */
4867     if (count == 0) {
4868                 cm_req_t req;
4869
4870                 cm_InitReq(&req);
4871
4872                 truncAttr.mask = CM_ATTRMASK_LENGTH;
4873         truncAttr.length.LowPart = offset.LowPart;
4874         truncAttr.length.HighPart = 0;
4875                 lock_ObtainMutex(&fidp->mx);
4876         code = cm_SetAttr(fidp->scp, &truncAttr, userp, &req);
4877                 lock_ReleaseMutex(&fidp->mx);
4878                 smb_SetSMBParm(outp, 0, /* count */ 0);
4879         smb_SetSMBDataLength(outp, 0);
4880                 fidp->flags |= SMB_FID_LENGTHSETDONE;
4881         goto done;
4882     }
4883
4884         /*
4885          * Work around bug in NT client
4886          *
4887          * When copying a file, the NT client should first copy the data,
4888          * then copy the last write time.  But sometimes the NT client does
4889          * these in the wrong order, so the data copies would inadvertently
4890          * cause the last write time to be overwritten.  We try to detect this,
4891          * and don't set client mod time if we think that would go against the
4892          * intention.
4893          */
4894         if ((fidp->flags & SMB_FID_MTIMESETDONE) != SMB_FID_MTIMESETDONE) {
4895                 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
4896                 fidp->scp->clientModTime = time(NULL);
4897         }
4898
4899 #ifndef DJGPP
4900         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
4901 #else /* DJGPP */
4902         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
4903 #endif /* !DJGPP */
4904         if (code == 0 && written < count)
4905                 code = CM_ERROR_PARTIALWRITE;
4906
4907         /* set the packet data length to 3 bytes for the data block header,
4908      * plus the size of the data.
4909      */
4910         smb_SetSMBParm(outp, 0, written);
4911     smb_SetSMBDataLength(outp, 0);
4912
4913   done:
4914     smb_ReleaseFID(fidp);
4915     cm_ReleaseUser(userp);
4916
4917         return code;
4918 }
4919
4920 void smb_CompleteWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
4921         NCB *ncbp, raw_write_cont_t *rwcp)
4922 {
4923         unsigned short fd;
4924         smb_fid_t *fidp;
4925         cm_user_t *userp;
4926 #ifndef DJGPP
4927         char *rawBuf;
4928 #else /* DJGPP */
4929         dos_ptr rawBuf;
4930 #endif /* !DJGPP */
4931         long written = 0;
4932         long code = 0;
4933
4934         fd = smb_GetSMBParm(inp, 0);
4935         fidp = smb_FindFID(vcp, fd, 0);
4936
4937         osi_Log2(smb_logp, "Completing Raw Write offset %x count %x",
4938                  rwcp->offset.LowPart, rwcp->count);
4939
4940         userp = smb_GetUser(vcp, inp);
4941
4942 #ifndef DJGPP
4943         rawBuf = rwcp->buf;
4944         code = smb_WriteData(fidp, &rwcp->offset, rwcp->count, rawBuf, userp,
4945                                                  &written);
4946 #else /* DJGPP */
4947         rawBuf = (dos_ptr) rwcp->buf;
4948         code = smb_WriteData(fidp, &rwcp->offset, rwcp->count,
4949                          (unsigned char *) rawBuf, userp,
4950                          &written, TRUE);
4951 #endif /* !DJGPP */
4952
4953         if (rwcp->writeMode & 0x1) {    /* synchronous */
4954                 smb_t *op;
4955
4956                 smb_FormatResponsePacket(vcp, inp, outp);
4957                 op = (smb_t *) outp;
4958                 op->com = 0x20;         /* SMB_COM_WRITE_COMPLETE */
4959                 smb_SetSMBParm(outp, 0, written + rwcp->alreadyWritten);
4960                 smb_SetSMBDataLength(outp,  0);
4961                 smb_SendPacket(vcp, outp);
4962                 smb_FreePacket(outp);
4963         }
4964         else {                          /* asynchronous */
4965                 lock_ObtainMutex(&fidp->mx);
4966                 fidp->raw_writers--;
4967                 if (fidp->raw_writers == 0)
4968                         thrd_SetEvent(fidp->raw_write_event);
4969                 lock_ReleaseMutex(&fidp->mx);
4970         }
4971
4972         /* Give back raw buffer */
4973         lock_ObtainMutex(&smb_RawBufLock);
4974 #ifndef DJGPP
4975         *((char **)rawBuf) = smb_RawBufs;
4976 #else /* DJGPP */
4977     _farpokel(_dos_ds, rawBuf, smb_RawBufs);
4978 #endif /* !DJGPP */
4979         smb_RawBufs = rawBuf;
4980         lock_ReleaseMutex(&smb_RawBufLock);
4981
4982         smb_ReleaseFID(fidp);
4983         cm_ReleaseUser(userp);
4984 }
4985
4986 long smb_ReceiveCoreWriteRawDummy(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
4987 {
4988         return 0;
4989 }
4990
4991 long smb_ReceiveCoreWriteRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp, raw_write_cont_t *rwcp)
4992 {
4993         osi_hyper_t offset;
4994     long count, written = 0;
4995         long totalCount;
4996     unsigned short fd;
4997     smb_fid_t *fidp;
4998     long code = 0;
4999     cm_user_t *userp;
5000     char *op;
5001         unsigned short writeMode;
5002 #ifndef DJGPP
5003         char *rawBuf;
5004 #else /* DJGPP */
5005     dos_ptr rawBuf;
5006 #endif /* !DJGPP */
5007
5008     fd = smb_GetSMBParm(inp, 0);
5009         totalCount = smb_GetSMBParm(inp, 1);
5010     count = smb_GetSMBParm(inp, 10);
5011     offset.HighPart = 0;        /* too bad */
5012     offset.LowPart = smb_GetSMBParm(inp, 3) | (smb_GetSMBParm(inp, 4) << 16);
5013         writeMode = smb_GetSMBParm(inp, 7);
5014
5015         op = (char *) inp->data;
5016         op += smb_GetSMBParm(inp, 11);
5017
5018     osi_Log4(smb_logp,
5019              "smb_ReceiveCoreWriteRaw fd %d, off 0x%x, size 0x%x, WriteMode 0x%x",
5020              fd, offset.LowPart, count, writeMode);
5021         
5022         fd = smb_ChainFID(fd, inp);
5023     fidp = smb_FindFID(vcp, fd, 0);
5024     if (!fidp) {
5025                 return CM_ERROR_BADFD;
5026     }
5027         
5028         userp = smb_GetUser(vcp, inp);
5029
5030         /*
5031          * Work around bug in NT client
5032          *
5033          * When copying a file, the NT client should first copy the data,
5034          * then copy the last write time.  But sometimes the NT client does
5035          * these in the wrong order, so the data copies would inadvertently
5036          * cause the last write time to be overwritten.  We try to detect this,
5037          * and don't set client mod time if we think that would go against the
5038          * intention.
5039          */
5040         if ((fidp->flags & SMB_FID_LOOKSLIKECOPY) != SMB_FID_LOOKSLIKECOPY) {
5041                 fidp->scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
5042                 fidp->scp->clientModTime = time(NULL);
5043         }
5044
5045 #ifndef DJGPP
5046         code = smb_WriteData(fidp, &offset, count, op, userp, &written);
5047 #else /* DJGPP */
5048         code = smb_WriteData(fidp, &offset, count, op, userp, &written, FALSE);
5049 #endif /* !DJGPP */
5050         if (code == 0 && written < count)
5051                 code = CM_ERROR_PARTIALWRITE;
5052
5053         /* Get a raw buffer */
5054         if (code == 0) {
5055                 rawBuf = NULL;
5056                 lock_ObtainMutex(&smb_RawBufLock);
5057                 if (smb_RawBufs) {
5058                         /* Get a raw buf, from head of list */
5059                         rawBuf = smb_RawBufs;
5060 #ifndef DJGPP
5061                         smb_RawBufs = *(char **)smb_RawBufs;
5062 #else /* DJGPP */
5063             smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
5064 #endif /* !DJGPP */
5065                 }
5066                 else
5067                         code = CM_ERROR_USESTD;
5068                 
5069         lock_ReleaseMutex(&smb_RawBufLock);
5070         }
5071
5072         /* Don't allow a premature Close */
5073         if (code == 0 && (writeMode & 1) == 0) {
5074                 lock_ObtainMutex(&fidp->mx);
5075                 fidp->raw_writers++;
5076                 thrd_ResetEvent(fidp->raw_write_event);
5077                 lock_ReleaseMutex(&fidp->mx);
5078         }
5079
5080         smb_ReleaseFID(fidp);
5081         cm_ReleaseUser(userp);
5082
5083         if (code) {
5084                 smb_SetSMBParm(outp, 0, written);
5085                 smb_SetSMBDataLength(outp, 0);
5086                 ((smb_t *)outp)->com = 0x20;    /* SMB_COM_WRITE_COMPLETE */
5087                 rwcp->code = code;
5088                 return code;
5089         }
5090
5091         rwcp->code = 0;
5092         rwcp->buf = rawBuf;
5093         rwcp->offset.HighPart = 0;
5094         rwcp->offset.LowPart = offset.LowPart + count;
5095         rwcp->count = totalCount - count;
5096         rwcp->writeMode = writeMode;
5097         rwcp->alreadyWritten = written;
5098
5099         /* set the packet data length to 3 bytes for the data block header,
5100      * plus the size of the data.
5101      */
5102         smb_SetSMBParm(outp, 0, 0xffff);
5103     smb_SetSMBDataLength(outp, 0);
5104
5105         return 0;
5106 }
5107
5108 long smb_ReceiveCoreRead(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5109 {
5110         osi_hyper_t offset;
5111     long count, finalCount;
5112     unsigned short fd;
5113     smb_fid_t *fidp;
5114     long code = 0;
5115     cm_user_t *userp;
5116     char *op;
5117         
5118     fd = smb_GetSMBParm(inp, 0);
5119     count = smb_GetSMBParm(inp, 1);
5120     offset.HighPart = 0;        /* too bad */
5121     offset.LowPart = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5122         
5123     osi_Log3(smb_logp, "smb_ReceiveCoreRead fd %d, off 0x%x, size 0x%x",
5124              fd, offset.LowPart, count);
5125         
5126         fd = smb_ChainFID(fd, inp);
5127     fidp = smb_FindFID(vcp, fd, 0);
5128     if (!fidp) {
5129                 return CM_ERROR_BADFD;
5130     }
5131         
5132     if (fidp->flags & SMB_FID_IOCTL) {
5133                 return smb_IoctlRead(fidp, vcp, inp, outp);
5134     }
5135         
5136         userp = smb_GetUser(vcp, inp);
5137
5138         /* remember this for final results */
5139     smb_SetSMBParm(outp, 0, count);
5140     smb_SetSMBParm(outp, 1, 0);
5141     smb_SetSMBParm(outp, 2, 0);
5142     smb_SetSMBParm(outp, 3, 0);
5143     smb_SetSMBParm(outp, 4, 0);
5144
5145         /* set the packet data length to 3 bytes for the data block header,
5146      * plus the size of the data.
5147      */
5148     smb_SetSMBDataLength(outp, count+3);
5149         
5150         /* get op ptr after putting in the parms, since otherwise we don't
5151      * know where the data really is.
5152      */
5153     op = smb_GetSMBData(outp, NULL);
5154
5155         /* now emit the data block header: 1 byte of type and 2 bytes of length */
5156     *op++ = 1;  /* data block marker */
5157     *op++ = (unsigned char) (count & 0xff);
5158     *op++ = (unsigned char) ((count >> 8) & 0xff);
5159                 
5160 #ifndef DJGPP
5161         code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount);
5162 #else /* DJGPP */
5163     code = smb_ReadData(fidp, &offset, count, op, userp, &finalCount, FALSE);
5164 #endif /* !DJGPP */
5165
5166         /* fix some things up */
5167         smb_SetSMBParm(outp, 0, finalCount);
5168         smb_SetSMBDataLength(outp, finalCount+3);
5169
5170     smb_ReleaseFID(fidp);
5171         
5172     cm_ReleaseUser(userp);
5173     return code;
5174 }
5175
5176 long smb_ReceiveCoreMakeDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5177 {
5178         char *pathp;
5179     long code = 0;
5180         cm_space_t *spacep;
5181     char *tp;
5182     cm_user_t *userp;
5183     cm_scache_t *dscp;                  /* dir we're dealing with */
5184     cm_scache_t *scp;                   /* file we're creating */
5185     cm_attr_t setAttr;
5186     int initialModeBits;
5187     char *lastNamep;
5188     int caseFold;
5189         char *tidPathp;
5190         cm_req_t req;
5191
5192         cm_InitReq(&req);
5193
5194     scp = NULL;
5195         
5196         /* compute initial mode bits based on read-only flag in attributes */
5197     initialModeBits = 0777;
5198         
5199         tp = smb_GetSMBData(inp, NULL);
5200     pathp = smb_ParseASCIIBlock(tp, &tp);
5201
5202         if (strcmp(pathp, "\\") == 0)
5203                 return CM_ERROR_EXISTS;
5204
5205         spacep = inp->spacep;
5206     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5207
5208         userp = smb_GetUser(vcp, inp);
5209
5210     caseFold = CM_FLAG_CASEFOLD;
5211
5212         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5213
5214         code = cm_NameI(cm_rootSCachep, spacep->data,
5215                     caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
5216                     userp, tidPathp, &req, &dscp);
5217
5218     if (code) {
5219         cm_ReleaseUser(userp);
5220         return code;
5221     }
5222         
5223     /* otherwise, scp points to the parent directory.  Do a lookup, and
5224          * fail if we find it.  Otherwise, we do the create.
5225      */
5226     if (!lastNamep) 
5227         lastNamep = pathp;
5228     else 
5229         lastNamep++;
5230     code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5231     if (scp) cm_ReleaseSCache(scp);
5232     if (code != CM_ERROR_NOSUCHFILE) {
5233         if (code == 0) code = CM_ERROR_EXISTS;
5234                 cm_ReleaseSCache(dscp);
5235         cm_ReleaseUser(userp);
5236         return code;
5237     }
5238         
5239         setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5240         setAttr.clientModTime = time(NULL);
5241         code = cm_MakeDir(dscp, lastNamep, 0, &setAttr, userp, &req);
5242         if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5243                 smb_NotifyChange(FILE_ACTION_ADDED,
5244                          FILE_NOTIFY_CHANGE_DIR_NAME,
5245                          dscp, lastNamep, NULL, TRUE);
5246         
5247         /* we don't need this any longer */
5248         cm_ReleaseSCache(dscp);
5249
5250     if (code) {
5251                 /* something went wrong creating or truncating the file */
5252         cm_ReleaseUser(userp);
5253         return code;
5254     }
5255         
5256         /* otherwise we succeeded */
5257     smb_SetSMBDataLength(outp, 0);
5258     cm_ReleaseUser(userp);
5259
5260     return 0;
5261 }
5262
5263 BOOL smb_IsLegalFilename(char *filename)
5264 {
5265     /* 
5266      *  Find the longest substring of filename that does not contain
5267      *  any of the chars in illegalChars.  If that substring is less
5268      *  than the length of the whole string, then one or more of the
5269      *  illegal chars is in filename. 
5270      */
5271     if (strcspn(filename, illegalChars) < strlen(filename))
5272         return FALSE;
5273
5274     return TRUE;
5275 }        
5276
5277 long smb_ReceiveCoreCreate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5278 {
5279         char *pathp;
5280     long code = 0;
5281         cm_space_t *spacep;
5282     char *tp;
5283     int excl;
5284     cm_user_t *userp;
5285     cm_scache_t *dscp;                  /* dir we're dealing with */
5286     cm_scache_t *scp;                   /* file we're creating */
5287     cm_attr_t setAttr;
5288     int initialModeBits;
5289     smb_fid_t *fidp;
5290     int attributes;
5291     char *lastNamep;
5292     int caseFold;
5293     long dosTime;
5294         char *tidPathp;
5295         cm_req_t req;
5296
5297         cm_InitReq(&req);
5298
5299     scp = NULL;
5300     excl = (inp->inCom == 0x03)? 0 : 1;
5301         
5302     attributes = smb_GetSMBParm(inp, 0);
5303     dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
5304         
5305         /* compute initial mode bits based on read-only flag in attributes */
5306     initialModeBits = 0666;
5307     if (attributes & 1) initialModeBits &= ~0222;
5308         
5309         tp = smb_GetSMBData(inp, NULL);
5310     pathp = smb_ParseASCIIBlock(tp, &tp);
5311
5312         spacep = inp->spacep;
5313     smb_StripLastComponent(spacep->data, &lastNamep, pathp);
5314
5315         userp = smb_GetUser(vcp, inp);
5316
5317     caseFold = CM_FLAG_CASEFOLD;
5318
5319         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
5320         code = cm_NameI(cm_rootSCachep, spacep->data, caseFold | CM_FLAG_FOLLOW,
5321                     userp, tidPathp, &req, &dscp);
5322
5323     if (code) {
5324         cm_ReleaseUser(userp);
5325         return code;
5326     }
5327         
5328     /* otherwise, scp points to the parent directory.  Do a lookup, and
5329          * truncate the file if we find it, otherwise we create the file.
5330      */
5331     if (!lastNamep) lastNamep = pathp;
5332     else lastNamep++;
5333
5334     if (!smb_IsLegalFilename(lastNamep))
5335         return CM_ERROR_BADNTFILENAME;
5336
5337     osi_Log1(smb_logp, "SMB receive create [%s]", osi_LogSaveString( smb_logp, pathp ));
5338 #ifdef DEBUG_VERBOSE
5339     {
5340         char *hexp;
5341         hexp = osi_HexifyString( lastNamep );
5342         DEBUG_EVENT2("AFS", "CoreCreate H[%s] A[%s]", hexp, lastNamep );
5343         free(hexp);
5344     }
5345 #endif    
5346
5347     code = cm_Lookup(dscp, lastNamep, caseFold, userp, &req, &scp);
5348     if (code && code != CM_ERROR_NOSUCHFILE) {
5349                 cm_ReleaseSCache(dscp);
5350         cm_ReleaseUser(userp);
5351         return code;
5352     }
5353         
5354     /* if we get here, if code is 0, the file exists and is represented by
5355      * scp.  Otherwise, we have to create it.
5356      */
5357         if (code == 0) {
5358                 if (excl) {
5359                         /* oops, file shouldn't be there */
5360             cm_ReleaseSCache(dscp);
5361             cm_ReleaseSCache(scp);
5362             cm_ReleaseUser(userp);
5363             return CM_ERROR_EXISTS;
5364         }
5365
5366                 setAttr.mask = CM_ATTRMASK_LENGTH;
5367         setAttr.length.LowPart = 0;
5368         setAttr.length.HighPart = 0;
5369                 code = cm_SetAttr(scp, &setAttr, userp, &req);
5370     }
5371     else {
5372                 setAttr.mask = CM_ATTRMASK_CLIENTMODTIME;
5373                 smb_UnixTimeFromDosUTime(&setAttr.clientModTime, dosTime);
5374         code = cm_Create(dscp, lastNamep, 0, &setAttr, &scp, userp,
5375                          &req);
5376                 if (code == 0 && (dscp->flags & CM_SCACHEFLAG_ANYWATCH))
5377                         smb_NotifyChange(FILE_ACTION_ADDED,
5378                              FILE_NOTIFY_CHANGE_FILE_NAME,
5379                              dscp, lastNamep, NULL, TRUE);
5380         if (!excl && code == CM_ERROR_EXISTS) {
5381                         /* not an exclusive create, and someone else tried
5382                          * creating it already, then we open it anyway.  We
5383                          * don't bother retrying after this, since if this next
5384                          * fails, that means that the file was deleted after
5385                          * we started this call.
5386              */
5387             code = cm_Lookup(dscp, lastNamep, caseFold, userp,
5388                              &req, &scp);
5389             if (code == 0) {
5390                                 setAttr.mask = CM_ATTRMASK_LENGTH;
5391                 setAttr.length.LowPart = 0;
5392                 setAttr.length.HighPart = 0;
5393                 code = cm_SetAttr(scp, &setAttr, userp, &req);
5394             }
5395         }
5396     }
5397         
5398         /* we don't need this any longer */
5399         cm_ReleaseSCache(dscp);
5400
5401     if (code) {
5402                 /* something went wrong creating or truncating the file */
5403         if (scp) cm_ReleaseSCache(scp);
5404         cm_ReleaseUser(userp);
5405         return code;
5406     }
5407
5408         /* make sure we only open files */
5409         if (scp->fileType != CM_SCACHETYPE_FILE) {
5410                 cm_ReleaseSCache(scp);
5411         cm_ReleaseUser(userp);
5412         return CM_ERROR_ISDIR;
5413         }
5414
5415     /* now all we have to do is open the file itself */
5416     fidp = smb_FindFID(vcp, 0, SMB_FLAG_CREATE);
5417     osi_assert(fidp);
5418         
5419         /* save a pointer to the vnode */
5420     fidp->scp = scp;
5421         
5422         /* always create it open for read/write */
5423         fidp->flags |= (SMB_FID_OPENREAD | SMB_FID_OPENWRITE);
5424
5425         smb_ReleaseFID(fidp);
5426         
5427         smb_SetSMBParm(outp, 0, fidp->fid);
5428     smb_SetSMBDataLength(outp, 0);
5429
5430         cm_Open(scp, 0, userp);
5431
5432     cm_ReleaseUser(userp);
5433     /* leave scp held since we put it in fidp->scp */
5434     return 0;
5435 }
5436
5437 long smb_ReceiveCoreSeek(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
5438 {
5439     long code = 0;
5440     long offset;
5441     int whence;
5442     unsigned short fd;
5443     smb_fid_t *fidp;
5444     cm_scache_t *scp;
5445     cm_user_t *userp;
5446         cm_req_t req;
5447
5448         cm_InitReq(&req);
5449         
5450     fd = smb_GetSMBParm(inp, 0);
5451         whence = smb_GetSMBParm(inp, 1);
5452     offset = smb_GetSMBParm(inp, 2) | (smb_GetSMBParm(inp, 3) << 16);
5453         
5454         /* try to find the file descriptor */
5455         fd = smb_ChainFID(fd, inp);
5456     fidp = smb_FindFID(vcp, fd, 0);
5457     if (!fidp || (fidp->flags & SMB_FID_IOCTL)) {
5458                 return CM_ERROR_BADFD;
5459     }
5460         
5461         userp = smb_GetUser(vcp, inp);
5462
5463     lock_ObtainMutex(&fidp->mx);
5464     scp = fidp->scp;
5465         lock_ObtainMutex(&scp->mx);
5466         code = cm_SyncOp(scp, NULL, userp, &req, 0,
5467                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
5468         if (code == 0) {
5469                 if (whence == 1) {
5470             /* offset from current offset */
5471             offset += fidp->offset;
5472                 }
5473                 else if (whence == 2) {
5474             /* offset from current EOF */
5475             offset += scp->length.LowPart;
5476                 }
5477         fidp->offset = offset;
5478         smb_SetSMBParm(outp, 0, offset & 0xffff);
5479         smb_SetSMBParm(outp, 1, (offset>>16) & 0xffff);
5480         smb_SetSMBDataLength(outp, 0);
5481     }
5482         lock_ReleaseMutex(&scp->mx);
5483     lock_ReleaseMutex(&fidp->mx);
5484     smb_ReleaseFID(fidp);
5485     cm_ReleaseUser(userp);
5486     return code;
5487 }
5488
5489 /* dispatch all of the requests received in a packet.  Due to chaining, this may
5490  * be more than one request.
5491  */
5492 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
5493         NCB *ncbp, raw_write_cont_t *rwcp)
5494 {
5495     smb_dispatch_t *dp;
5496     smb_t *smbp;
5497     unsigned long code = 0;
5498     unsigned char *outWctp;
5499     int nparms;                 /* # of bytes of parameters */
5500     char tbuffer[200];
5501     int nbytes;                 /* bytes of data, excluding count */
5502     int temp;
5503     unsigned char *tp;
5504     unsigned short errCode;
5505         unsigned long NTStatus;
5506     int noSend;
5507     unsigned char errClass;
5508         unsigned int oldGen;
5509         DWORD oldTime, newTime;
5510
5511         /* get easy pointer to the data */
5512         smbp = (smb_t *) inp->data;
5513
5514         if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED)) {
5515         /* setup the basic parms for the initial request in the packet */
5516                 inp->inCom = smbp->com;
5517         inp->wctp = &smbp->wct;
5518         inp->inCount = 0;
5519                 inp->ncb_length = ncbp->ncb_length;
5520         }
5521     noSend = 0;
5522
5523         /* Sanity check */
5524         if (ncbp->ncb_length < offsetof(struct smb, vdata)) {
5525                 /* log it and discard it */
5526 #ifndef DJGPP
5527                 HANDLE h;
5528                 char *ptbuf[1];
5529                 char s[100];
5530                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5531                 sprintf(s, "SMB message too short, len %d", ncbp->ncb_length);
5532                 ptbuf[0] = s;
5533                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1007, NULL,
5534                         1, ncbp->ncb_length, ptbuf, inp);
5535                 DeregisterEventSource(h);
5536 #else /* DJGPP */
5537         osi_Log1(smb_logp, "SMB message too short, len %d",
5538                  ncbp->ncb_length);
5539 #endif /* !DJGPP */
5540
5541                 return;
5542         }
5543
5544         /* We are an ongoing op */
5545         thrd_Increment(&ongoingOps);
5546
5547     /* set up response packet for receiving output */
5548         if (!(outp->flags & SMB_PACKETFLAG_SUSPENDED))
5549         smb_FormatResponsePacket(vcp, inp, outp);
5550     outWctp = outp->wctp;
5551
5552         /* Remember session generation number and time */
5553         oldGen = sessionGen;
5554         oldTime = GetCurrentTime();
5555
5556         while(inp->inCom != 0xff) {
5557         dp = &smb_dispatchTable[inp->inCom];
5558
5559                 if (outp->flags & SMB_PACKETFLAG_SUSPENDED) {
5560                         outp->flags &= ~SMB_PACKETFLAG_SUSPENDED;
5561                         code = outp->resumeCode;
5562                         goto resume;
5563                 }
5564
5565         /* process each request in the packet; inCom, wctp and inCount
5566          * are already set up.
5567          */
5568                 osi_Log2(smb_logp, "SMB received op 0x%x lsn %d", inp->inCom,
5569                  ncbp->ncb_lsn);
5570
5571                 /* now do the dispatch */
5572                 /* start by formatting the response record a little, as a default */
5573         if (dp->flags & SMB_DISPATCHFLAG_CHAINED) {
5574                         outWctp[0] = 2;
5575             outWctp[1] = 0xff;  /* no operation */
5576             outWctp[2] = 0;             /* padding */
5577             outWctp[3] = 0;
5578             outWctp[4] = 0;
5579         }
5580                 else {
5581                         /* not a chained request, this is a more reasonable default */
5582             outWctp[0] = 0;     /* wct of zero */
5583             outWctp[1] = 0;     /* and bcc (word) of zero */
5584             outWctp[2] = 0;
5585                 }   
5586
5587                 /* once set, stays set.  Doesn't matter, since we never chain
5588          * "no response" calls.
5589          */
5590                 if (dp->flags & SMB_DISPATCHFLAG_NORESPONSE)
5591             noSend = 1;
5592
5593         if (dp->procp) {
5594                         /* we have a recognized operation */
5595
5596                         if (inp->inCom == 0x1d)
5597                                 /* Raw Write */
5598                                 code = smb_ReceiveCoreWriteRaw (vcp, inp, outp,
5599                                                 rwcp);
5600                         else {
5601                                         osi_LogEvent("AFS Dispatch %s",(myCrt_Dispatch(inp->inCom)),"vcp[%x] lana[%d] lsn[%d]",(int)vcp,vcp->lana,vcp->lsn);
5602                                         osi_Log4(smb_logp,"Dispatch %s vcp[%x] lana[%d] lsn[%d]",(myCrt_Dispatch(inp->inCom)),vcp,vcp->lana,vcp->lsn);
5603                                         code = (*(dp->procp)) (vcp, inp, outp);
5604                                         osi_LogEvent("AFS Dispatch return",NULL,"Code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5605                                         osi_Log1(smb_logp,"Dispatch return  code[%d]",(code==0)?0:code-CM_ERROR_BASE);
5606             }
5607
5608                         if (oldGen != sessionGen) {
5609 #ifndef DJGPP
5610                                 HANDLE h;
5611                                 char *ptbuf[1];
5612                                 char s[100];
5613                                 newTime = GetCurrentTime();
5614                                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5615                                 sprintf(s, "Pkt straddled session startup, took %d ms, ncb length %d",
5616                         newTime - oldTime, ncbp->ncb_length);
5617                                 ptbuf[0] = s;
5618                                 ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
5619                             1005, NULL, 1, ncbp->ncb_length, ptbuf, smbp);
5620                                 DeregisterEventSource(h);
5621 #else /* DJGPP */
5622                                 osi_Log1(smb_logp, "Pkt straddled session startup, "
5623                          "ncb length %d", ncbp->ncb_length);
5624 #endif /* !DJGPP */
5625                         }
5626         }
5627         else {
5628                         /* bad opcode, fail the request, after displaying it */
5629 #ifdef NOTSERVICE
5630             smb_LogPacket(inp);
5631 #endif  /* NOTSERVICE */
5632
5633 #ifndef DJGPP
5634                         if (showErrors) {
5635                                 sprintf(tbuffer, "Received bad SMB req 0x%x", inp->inCom);
5636                 code = (*smb_MBfunc)(NULL, tbuffer, "Cancel: don't show again",
5637                                      MB_OKCANCEL|MB_SERVICE_NOTIFICATION);
5638                 if (code == IDCANCEL) showErrors = 0;
5639                         }
5640 #endif /* DJGPP */
5641             code = CM_ERROR_BADOP;
5642         }
5643
5644                 /* catastrophic failure:  log as much as possible */
5645                 if (code == CM_ERROR_BADSMB) {
5646 #ifndef DJGPP
5647                         HANDLE h;
5648                         char *ptbuf[1];
5649                         char s[100];
5650
5651                         osi_Log1(smb_logp,
5652                       "Invalid SMB, ncb_length %d",
5653                       ncbp->ncb_length);
5654
5655                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
5656                         sprintf(s, "Invalid SMB message, length %d",
5657                      ncbp->ncb_length);
5658                         ptbuf[0] = s;
5659                         ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1002, NULL,
5660                          1, ncbp->ncb_length, ptbuf, smbp);
5661                         DeregisterEventSource(h);
5662 #ifdef NOTSERVICE
5663             smb_LogPacket(inp);
5664 #endif /* NOTSERVICE */
5665 #else /* DJGPP */
5666             osi_Log1(smb_logp, "Invalid SMB message, length %d",
5667                      ncbp->ncb_length);
5668 #endif /* !DJGPP */
5669
5670                         code = CM_ERROR_INVAL;
5671                 }
5672
5673                 if (outp->flags & SMB_PACKETFLAG_NOSEND) {
5674                         thrd_Decrement(&ongoingOps);
5675                         return;
5676                 }
5677
5678       resume:
5679                 /* now, if we failed, turn the current response into an empty
5680          * one, and fill in the response packet's error code.
5681          */
5682                 if (code) {
5683                         if (vcp->flags & SMB_VCFLAG_STATUS32) {
5684                                 smb_MapNTError(code, &NTStatus);
5685                                 outWctp = outp->wctp;
5686                                 smbp = (smb_t *) &outp->data;
5687                                 if (code != CM_ERROR_PARTIALWRITE
5688                                     && code != CM_ERROR_BUFFERTOOSMALL) {
5689                                         /* nuke wct and bcc.  For a partial
5690                                          * write, assume they're OK.
5691                                          */
5692                                         *outWctp++ = 0;
5693                                         *outWctp++ = 0;
5694                                         *outWctp++ = 0;
5695                                 }
5696                                 smbp->rcls = (unsigned char) (NTStatus & 0xff);
5697                                 smbp->reh = (unsigned char) ((NTStatus >> 8) & 0xff);
5698                                 smbp->errLow = (unsigned char) ((NTStatus >> 16) & 0xff);
5699                                 smbp->errHigh = (unsigned char) ((NTStatus >> 24) & 0xff);
5700                                 smbp->flg2 |= 0x4000;
5701                                 break;
5702                         }
5703                         else {
5704                 smb_MapCoreError(code, vcp, &errCode, &errClass);
5705                                 outWctp = outp->wctp;
5706                                 smbp = (smb_t *) &outp->data;
5707                                 if (code != CM_ERROR_PARTIALWRITE) {
5708                                         /* nuke wct and bcc.  For a partial
5709                                          * write, assume they're OK.
5710                                          */
5711                                         *outWctp++ = 0;
5712                                         *outWctp++ = 0;
5713                                         *outWctp++ = 0;
5714                                 }
5715                                 smbp->errLow = (unsigned char) (errCode & 0xff);
5716                                 smbp->errHigh = (unsigned char) ((errCode >> 8) & 0xff);
5717                 smbp->rcls = errClass;
5718                                 break;
5719                         }
5720                 }       /* error occurred */
5721                 
5722         /* if we're here, we've finished one request.  Look to see if
5723                  * this is a chained opcode.  If it is, setup things to process
5724                  * the chained request, and setup the output buffer to hold the
5725                  * chained response.  Start by finding the next input record.
5726          */
5727         if (!(dp->flags & SMB_DISPATCHFLAG_CHAINED))
5728             break;              /* not a chained req */
5729         tp = inp->wctp;         /* points to start of last request */
5730         /* in a chained request, the first two
5731          * parm fields are required, and are
5732          * AndXCommand/AndXReserved and
5733          * AndXOffset. */
5734         if (tp[0] < 2) break;   
5735         if (tp[1] == 0xff) break;       /* no more chained opcodes */
5736         inp->inCom = tp[1];
5737         inp->wctp = inp->data + tp[3] + (tp[4] << 8);
5738         inp->inCount++;
5739
5740         /* and now append the next output request to the end of this
5741          * last request.  Begin by finding out where the last response
5742                  * ends, since that's where we'll put our new response.
5743          */
5744         outWctp = outp->wctp;           /* ptr to out parameters */
5745         osi_assert (outWctp[0] >= 2);   /* need this for all chained requests */
5746         nparms = outWctp[0] << 1;
5747         tp = outWctp + nparms + 1;      /* now points to bcc field */
5748         nbytes = tp[0] + (tp[1] << 8);  /* # of data bytes */
5749         tp += 2 /* for the count itself */ + nbytes;
5750                 /* tp now points to the new output record; go back and patch the
5751          * second parameter (off2) to point to the new record.
5752          */
5753                 temp = (unsigned int)tp - ((unsigned int) outp->data);
5754         outWctp[3] = (unsigned char) (temp & 0xff);
5755         outWctp[4] = (unsigned char) ((temp >> 8) & 0xff);
5756         outWctp[2] = 0; /* padding */
5757         outWctp[1] = inp->inCom;        /* next opcode */
5758
5759                 /* finally, setup for the next iteration */
5760         outp->wctp = tp;
5761                 outWctp = tp;
5762         }       /* while loop over all requests in the packet */
5763
5764         /* done logging out, turn off logging-out flag */
5765         if (!(inp->flags & SMB_PACKETFLAG_PROFILE_UPDATE_OK)) {
5766                 vcp->justLoggedOut = NULL;
5767                 if (loggedOut) {
5768                         loggedOut = 0;
5769                         free(loggedOutName);
5770                         loggedOutName = NULL;
5771                         smb_ReleaseUID(loggedOutUserp);
5772                         loggedOutUserp = NULL;
5773                 }
5774         }
5775  
5776     /* now send the output packet, and return */
5777     if (!noSend)
5778                 smb_SendPacket(vcp, outp);
5779         thrd_Decrement(&ongoingOps);
5780
5781         if (!(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
5782                 active_vcp = vcp;
5783                 last_msg_time = GetCurrentTime();
5784         }
5785         else if (active_vcp == vcp)
5786                 active_vcp = NULL;
5787
5788     return;
5789 }
5790
5791 #ifndef DJGPP
5792 /* Wait for Netbios() calls to return, and make the results available to server
5793  * threads.  Note that server threads can't wait on the NCBevents array
5794  * themselves, because NCB events are manual-reset, and the servers would race
5795  * each other to reset them.
5796  */
5797 void smb_ClientWaiter(void *parmp)
5798 {
5799         DWORD code;
5800     int   idx;
5801
5802         while (1) {
5803                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBevents,
5804                                               FALSE, INFINITE);
5805                 if (code == WAIT_OBJECT_0)
5806                         continue;
5807
5808         /* error checking */
5809         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5810         {
5811             int abandonIdx = code - WAIT_ABANDONED_0;
5812             afsi_log("Error: smb_ClientWaiter event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5813         }
5814
5815         if (code == WAIT_IO_COMPLETION)
5816         {
5817             afsi_log("Error: smb_ClientWaiter WAIT_IO_COMPLETION\n");
5818             continue;
5819         }
5820         
5821         if (code == WAIT_TIMEOUT)
5822         {
5823             afsi_log("Error: smb_ClientWaiter WAIT_TIMEOUT, errno %d\n", GetLastError());
5824         }
5825
5826         if (code == WAIT_FAILED)
5827         {
5828             afsi_log("Error: smb_ClientWaiter WAIT_FAILED, errno %d\n", GetLastError());
5829         }
5830
5831         idx = code - WAIT_OBJECT_0;
5832  
5833         /* check idx range! */
5834         if (idx < 0 || idx > (sizeof(NCBevents) / sizeof(NCBevents[0])))
5835         {
5836             /* this is fatal - log as much as possible */
5837             afsi_log("Fatal: NCBevents idx [ %d ] out of range.\n", idx);
5838             osi_assert(0);
5839         }
5840         
5841                 thrd_ResetEvent(NCBevents[idx]);
5842                 thrd_SetEvent(NCBreturns[0][idx]);
5843         }
5844 }
5845 #endif /* !DJGPP */
5846
5847 /*
5848  * Try to have one NCBRECV request waiting for every live session.  Not more
5849  * than one, because if there is more than one, it's hard to handle Write Raw.
5850  */
5851 void smb_ServerWaiter(void *parmp)
5852 {
5853         DWORD code;
5854     int idx_session, idx_NCB;
5855         NCB *ncbp;
5856 #ifdef DJGPP
5857     dos_ptr dos_ncb;
5858 #endif /* DJGPP */
5859
5860         while (1) {
5861                 /* Get a session */
5862                 code = thrd_WaitForMultipleObjects_Event(numSessions, SessionEvents,
5863                                                    FALSE, INFINITE);
5864                 if (code == WAIT_OBJECT_0)
5865                         continue;
5866
5867         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numSessions))
5868         {
5869             int abandonIdx = code - WAIT_ABANDONED_0;
5870             afsi_log("Error: smb_ServerWaiter (SessionEvents) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5871         }
5872         
5873         if (code == WAIT_IO_COMPLETION)
5874         {
5875             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_IO_COMPLETION\n");
5876             continue;
5877         }
5878         
5879         if (code == WAIT_TIMEOUT)
5880         {
5881             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_TIMEOUT, errno %d\n", GetLastError());
5882         }
5883         
5884         if (code == WAIT_FAILED)
5885         {
5886             afsi_log("Error: smb_ServerWaiter (SessionEvents) WAIT_FAILED, errno %d\n", GetLastError());
5887         }
5888         
5889         idx_session = code - WAIT_OBJECT_0;
5890
5891         /* check idx range! */
5892         if (idx_session < 0 || idx_session > (sizeof(SessionEvents) / sizeof(SessionEvents[0])))
5893         {
5894             /* this is fatal - log as much as possible */
5895             afsi_log("Fatal: session idx [ %d ] out of range.\n", idx_session);
5896             osi_assert(0);
5897         }
5898
5899                 /* Get an NCB */
5900       NCBretry:
5901                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBavails,
5902                                                    FALSE, INFINITE);
5903                 if (code == WAIT_OBJECT_0)
5904                         goto NCBretry;
5905
5906         /* error checking */
5907         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
5908         {
5909             int abandonIdx = code - WAIT_ABANDONED_0;
5910             afsi_log("Error: smb_ClientWaiter (NCBavails) event %d abandoned, errno %d\n", abandonIdx, GetLastError());
5911         }
5912         
5913         if (code == WAIT_IO_COMPLETION)
5914         {
5915             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_IO_COMPLETION\n");
5916             continue;
5917         }
5918         
5919         if (code == WAIT_TIMEOUT)
5920         {
5921             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_TIMEOUT, errno %d\n", GetLastError());
5922         }
5923         
5924         if (code == WAIT_FAILED)
5925         {
5926             afsi_log("Error: smb_ClientWaiter (NCBavails) WAIT_FAILED, errno %d\n", GetLastError());
5927         }
5928                 
5929         idx_NCB = code - WAIT_OBJECT_0;
5930
5931         /* check idx range! */
5932         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBsessions) / sizeof(NCBsessions[0])))
5933         {
5934             /* this is fatal - log as much as possible */
5935             afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
5936             osi_assert(0);
5937         }
5938
5939                 /* Link them together */
5940                 NCBsessions[idx_NCB] = idx_session;
5941
5942                 /* Fire it up */
5943                 ncbp = NCBs[idx_NCB];
5944 #ifdef DJGPP
5945         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
5946 #endif /* DJGPP */
5947                 ncbp->ncb_lsn = (unsigned char) LSNs[idx_session];
5948                 ncbp->ncb_command = NCBRECV | ASYNCH;
5949                 ncbp->ncb_lana_num = lanas[idx_session];
5950 #ifndef DJGPP
5951                 ncbp->ncb_buffer = (unsigned char *) bufs[idx_NCB];
5952                 ncbp->ncb_event = NCBevents[idx_NCB];
5953                 ncbp->ncb_length = SMB_PACKETSIZE;
5954                 Netbios(ncbp);
5955 #else /* DJGPP */
5956                 ncbp->ncb_buffer = bufs[idx_NCB]->dos_pkt;
5957                 ((smb_ncb_t*)ncbp)->orig_pkt = bufs[idx_NCB];
5958                 ncbp->ncb_event = NCBreturns[0][idx_NCB];
5959                 ncbp->ncb_length = SMB_PACKETSIZE;
5960                 Netbios(ncbp, dos_ncb);
5961 #endif /* !DJGPP */
5962         }
5963 }
5964
5965 /*
5966  * The top level loop for handling SMB request messages.  Each server thread
5967  * has its own NCB and buffer for sending replies (outncbp, outbufp), but the
5968  * NCB and buffer for the incoming request are loaned to us.
5969  *
5970  * Write Raw trickery starts here.  When we get a Write Raw, we are supposed
5971  * to immediately send a request for the rest of the data.  This must come
5972  * before any other traffic for that session, so we delay setting the session
5973  * event until that data has come in.
5974  */
5975 void smb_Server(VOID *parmp)
5976 {
5977         int myIdx = (int) parmp;
5978         NCB *ncbp;
5979         NCB *outncbp;
5980     smb_packet_t *bufp;
5981         smb_packet_t *outbufp;
5982     DWORD code, rcode;
5983     int idx_NCB, idx_session;
5984         UCHAR rc;
5985         smb_vc_t *vcp;
5986         smb_t *smbp;
5987 #ifdef DJGPP
5988     dos_ptr dos_ncb;
5989 #endif /* DJGPP */
5990
5991         outncbp = GetNCB();
5992         outbufp = GetPacket();
5993         outbufp->ncbp = outncbp;
5994
5995         while (1) {
5996 #ifndef NOEXPIRE
5997                 /* check for demo expiration */
5998                 {
5999                         unsigned long tod = time((void *) 0);
6000                         if (tod > EXPIREDATE) {
6001                                 (*smb_MBfunc)(NULL, "AFS demo expiration",
6002                                            "afsd dispatcher",
6003                                            MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6004                                 trhd_Exit(1);
6005                         }
6006                 }
6007 #endif /* !NOEXPIRE */
6008
6009                 code = thrd_WaitForMultipleObjects_Event(numNCBs, NCBreturns[myIdx],
6010                                                    FALSE, INFINITE);
6011                 if (code == WAIT_OBJECT_0) {
6012                         continue;
6013         }
6014
6015         /* error checking */
6016         if (code >= WAIT_ABANDONED_0 && code < (WAIT_ABANDONED_0 + numNCBs))
6017         {
6018             int abandonIdx = code - WAIT_ABANDONED_0;
6019             afsi_log("Error: smb_Server ( NCBreturns[%d] ) event %d abandoned, errno %d\n", myIdx, abandonIdx, GetLastError());
6020         }
6021         
6022         if (code == WAIT_IO_COMPLETION)
6023         {
6024             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_IO_COMPLETION\n", myIdx);
6025             continue;
6026         }
6027         
6028         if (code == WAIT_TIMEOUT)
6029         {
6030             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_TIMEOUT, errno %d\n", myIdx, GetLastError());
6031         }
6032         
6033         if (code == WAIT_FAILED)
6034         {
6035             afsi_log("Error: smb_Server ( NCBreturns[%d] ) WAIT_FAILED, errno %d\n", myIdx, GetLastError());
6036         }
6037
6038         idx_NCB = code - WAIT_OBJECT_0;
6039         
6040         /* check idx range! */
6041         if (idx_NCB < 0 || idx_NCB > (sizeof(NCBs) / sizeof(NCBs[0])))
6042         {
6043             /* this is fatal - log as much as possible */
6044             afsi_log("Fatal: idx_NCB [ %d ] out of range.\n", idx_NCB);
6045             osi_assert(0);
6046         }
6047
6048                 ncbp = NCBs[idx_NCB];
6049 #ifdef DJGPP
6050                 dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6051 #endif /* DJGPP */
6052                 idx_session = NCBsessions[idx_NCB];
6053                 rc = ncbp->ncb_retcode;
6054
6055                 if (rc != NRC_PENDING && rc != NRC_GOODRET)
6056                         osi_Log1(smb_logp, "NCBRECV failure code %d", rc);
6057
6058                 switch (rc) {
6059                         case NRC_GOODRET: break;
6060
6061                         case NRC_PENDING:
6062                                 /* Can this happen? Or is it just my
6063                                  * UNIX paranoia? 
6064                  */
6065                                 continue;
6066
6067                         case NRC_SCLOSED:
6068                         case NRC_SNUMOUT:
6069                                 /* Client closed session */
6070                 if (reportSessionStartups) 
6071                 {
6072                     afsi_log("session [ %d ] closed", idx_session);
6073                 }
6074                                 dead_sessions[idx_session] = TRUE;
6075                                 vcp = smb_FindVC(ncbp->ncb_lsn, 0, lanas[idx_session]);
6076                                 /* Should also release vcp.  Also, would do
6077                                  * sanity check that all TID's are gone. 
6078                  *
6079                  * TODO: check if we could use LSNs[idx_session] instead, 
6080                  * also cleanup after dead vcp 
6081                  */
6082                 if (vcp) {
6083                     if (dead_vcp)
6084                         osi_Log1(smb_logp,
6085                                   "dead_vcp already set, %x",
6086                                   dead_vcp);
6087                     if (!dead_vcp && !(vcp->flags & SMB_VCFLAG_ALREADYDEAD)) {
6088                         osi_Log2(smb_logp,
6089                                   "setting dead_vcp %x, user struct %x",
6090                                   vcp, vcp->usersp);
6091                         dead_vcp = vcp;
6092                         vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
6093                     }
6094                     if (vcp->justLoggedOut) {
6095                         loggedOut = 1;
6096                         loggedOutTime = vcp->logoffTime;
6097                         loggedOutName =
6098                             strdup(vcp->justLoggedOut->unp->name);
6099                         loggedOutUserp = vcp->justLoggedOut;
6100                         lock_ObtainWrite(&smb_rctLock);
6101                         loggedOutUserp->refCount++;
6102                         lock_ReleaseWrite(&smb_rctLock);
6103                     }
6104                 }
6105                                 goto doneWithNCB;
6106
6107                         case NRC_INCOMP:
6108                                 /* Treat as transient error */
6109                                 {
6110 #ifndef DJGPP
6111                                         EVENT_HANDLE h;
6112                                         char *ptbuf[1];
6113                                         char s[100];
6114
6115                                         osi_Log1(smb_logp, "dispatch smb recv failed, message incomplete, ncb_length %d",
6116                              ncbp->ncb_length);
6117                                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6118                                         sprintf(s, "SMB message incomplete, length %d",
6119                             ncbp->ncb_length);
6120                                         ptbuf[0] = s;
6121                                         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0,
6122                                 1001, NULL, 1,
6123                                 ncbp->ncb_length, ptbuf,
6124                                 bufp);
6125                                         DeregisterEventSource(h);
6126 #else /* DJGPP */
6127                                         osi_Log1(smb_logp,
6128                               "dispatch smb recv failed, message incomplete, ncb_length %d",
6129                               ncbp->ncb_length);
6130                     osi_Log1(smb_logp,
6131                               "SMB message incomplete, "
6132                               "length %d", ncbp->ncb_length);
6133 #endif /* !DJGPP */
6134
6135                                         /*
6136                                          * We used to discard the packet.
6137                                          * Instead, try handling it normally.
6138                                          *
6139                      continue;
6140                                          */
6141                                         break;
6142                                 }
6143
6144                         default:
6145                                 /* A weird error code.  Log it, sleep, and
6146                                  * continue. */
6147                                 if (vcp->errorCount++ > 3) {
6148                     afsi_log("session [ %d ] closed, vcp->errorCount = %d", idx_session, vcp->errorCount);
6149                                         dead_sessions[idx_session] = TRUE;
6150                 }
6151                                 else {
6152                                         thrd_Sleep(1000);
6153                                         thrd_SetEvent(SessionEvents[idx_session]);
6154                                 }
6155                                 continue;
6156                 }
6157
6158                 /* Success, so now dispatch on all the data in the packet */
6159
6160                 smb_concurrentCalls++;
6161                 if (smb_concurrentCalls > smb_maxObsConcurrentCalls)
6162                         smb_maxObsConcurrentCalls = smb_concurrentCalls;
6163
6164                 vcp = smb_FindVC(ncbp->ncb_lsn, 0, ncbp->ncb_lana_num);
6165         /*
6166                 * If at this point vcp is NULL (implies that packet was invalid)
6167                 * then we are in big trouble. This means either :
6168                 *   a) we have the wrong NCB.
6169                 *   b) Netbios screwed up the call.
6170                 * Obviously this implies that 
6171                 *   ( LSNs[idx_session] != ncbp->ncb_lsn ||
6172                 *   lanas[idx_session] != ncbp->ncb_lana_num )
6173                 * Either way, we can't do anything with this packet.
6174                 * Log, sleep and resume.
6175                 */
6176                 if(!vcp) {
6177                         HANDLE h;
6178                         char buf[1000];
6179                         char *ptbuf[1];
6180
6181                         sprintf(buf,
6182                                 "Bad vcp!! : "
6183                                 "LSNs[idx_session]=[%d],"
6184                                 "lanas[idx_session]=[%d],"
6185                                 "ncbp->ncb_lsn=[%d],"
6186                                 "ncbp->ncb_lana_num=[%d]",
6187                                 LSNs[idx_session],
6188                                 lanas[idx_session],
6189                                 ncbp->ncb_lsn,
6190                                 ncbp->ncb_lana_num);
6191
6192                         ptbuf[0] = buf;
6193
6194                         h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6195                         if(h) {
6196                                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,sizeof(*ncbp),ptbuf,(void*)ncbp);
6197                                 DeregisterEventSource(h);
6198                         }
6199
6200                         /* Also log in the trace log. */
6201                         osi_Log4(smb_logp, "Server: BAD VCP!"
6202                                 "LSNs[idx_session]=[%d],"
6203                                 "lanas[idx_session]=[%d],"
6204                                 "ncbp->ncb_lsn=[%d],"
6205                                 "ncbp->ncb_lana_num=[%d]",
6206                                 LSNs[idx_session],
6207                                 lanas[idx_session],
6208                                 ncbp->ncb_lsn,
6209                                 ncbp->ncb_lana_num);
6210
6211                         /* thrd_Sleep(1000); Don't bother sleeping */
6212                         thrd_SetEvent(SessionEvents[idx_session]);
6213                         smb_concurrentCalls--;
6214                         continue;
6215                 }
6216
6217
6218                 vcp->errorCount = 0;
6219                 bufp = (struct smb_packet *) ncbp->ncb_buffer;
6220 #ifdef DJGPP
6221                 bufp = ((smb_ncb_t *) ncbp)->orig_pkt;
6222         /* copy whole packet to virtual memory */
6223         /*fprintf(stderr, "smb_Server: copying dos packet at 0x%x, "
6224         "bufp=0x%x\n",
6225         bufp->dos_pkt / 16, bufp);*/
6226         fflush(stderr);
6227         dosmemget(bufp->dos_pkt, ncbp->ncb_length, bufp->data);
6228 #endif /* DJGPP */
6229                 smbp = (smb_t *)bufp->data;
6230                 outbufp->flags = 0;
6231
6232 #if !defined(DJGPP) && !defined(AFS_WIN32_ENV)
6233         __try
6234         {
6235 #endif
6236                 if (smbp->com == 0x1d) {
6237                         /* Special handling for Write Raw */
6238                         raw_write_cont_t rwc;
6239                         EVENT_HANDLE rwevent;
6240             char eventName[MAX_PATH];
6241             
6242             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, &rwc);
6243                         if (rwc.code == 0) {
6244                                 rwevent = thrd_CreateEvent(NULL, FALSE, FALSE, TEXT("smb_Server() rwevent"));
6245                 if ( GetLastError() == ERROR_ALREADY_EXISTS )
6246                     afsi_log("Event Object Already Exists: %s", eventName);
6247                                 ncbp->ncb_command = NCBRECV | ASYNCH;
6248                                 ncbp->ncb_lsn = (unsigned char) vcp->lsn;
6249                                 ncbp->ncb_lana_num = vcp->lana;
6250                                 ncbp->ncb_buffer = rwc.buf;
6251                                 ncbp->ncb_length = 65535;
6252                                 ncbp->ncb_event = rwevent;
6253 #ifndef DJGPP
6254                                 Netbios(ncbp);
6255 #else
6256                                 Netbios(ncbp, dos_ncb);
6257 #endif /* !DJGPP */
6258                                 rcode = thrd_WaitForSingleObject_Event(rwevent, RAWTIMEOUT);
6259                                 thrd_CloseHandle(rwevent);
6260                         }
6261                         thrd_SetEvent(SessionEvents[idx_session]);
6262                         if (rwc.code == 0)
6263                                 smb_CompleteWriteRaw(vcp, bufp, outbufp, ncbp, &rwc);
6264                 } else if (smbp->com == 0xa0) { 
6265             /* 
6266              * Serialize the handling for NT Transact 
6267              * (defect 11626)
6268              */
6269             smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6270                         thrd_SetEvent(SessionEvents[idx_session]);
6271         } else {
6272                         thrd_SetEvent(SessionEvents[idx_session]);
6273             /* TODO: what else needs to be serialized? */
6274                         smb_DispatchPacket(vcp, bufp, outbufp, ncbp, NULL);
6275                 }
6276 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6277         }
6278         __except( smb_ServerExceptionFilter() ) {
6279         }
6280 #endif
6281
6282                 smb_concurrentCalls--;
6283
6284 doneWithNCB:
6285                 thrd_SetEvent(NCBavails[idx_NCB]);
6286         }
6287 }
6288
6289 /*
6290  * Exception filter for the server threads.  If an exception occurs in the
6291  * dispatch routines, which is where exceptions are most common, then do a
6292  * force trace and give control to upstream exception handlers. Useful for
6293  * debugging.
6294  */
6295 #if !defined(DJGPP) && !defined(AFS_WIN95_ENV)
6296 DWORD smb_ServerExceptionFilter(void) {
6297         /* While this is not the best time to do a trace, if it succeeds, then
6298          * we have a trace (assuming tracing was enabled). Otherwise, this should
6299          * throw a second exception.
6300          */
6301         HANDLE h;
6302         char *ptbuf[1];
6303
6304         ptbuf[0] = "Unhandled exception forcing trace";
6305
6306         h = RegisterEventSource(NULL,AFS_DAEMON_EVENT_NAME);
6307         if(h) {
6308                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1001, NULL,1,0,ptbuf,NULL);
6309                 DeregisterEventSource(h);
6310         }
6311
6312         afsd_ForceTrace(TRUE);
6313         return EXCEPTION_CONTINUE_SEARCH;
6314 }
6315 #endif
6316
6317 /*
6318  * Create a new NCB and associated events, packet buffer, and "space" buffer.
6319  * If the number of server threads is M, and the number of live sessions is
6320  * N, then the number of NCB's in use at any time either waiting for, or
6321  * holding, received messages is M + N, so that is how many NCB's get created.
6322  */
6323 void InitNCBslot(int idx)
6324 {
6325         struct smb_packet *bufp;
6326         EVENT_HANDLE retHandle;
6327         int i;
6328     char eventName[MAX_PATH];
6329
6330     osi_assert( idx < (sizeof(NCBs) / sizeof(NCBs[0])) );
6331
6332         NCBs[idx] = GetNCB();
6333     sprintf(eventName,"NCBavails[%d]", idx);
6334         NCBavails[idx] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6335     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6336         afsi_log("Event Object Already Exists: %s", eventName);
6337 #ifndef DJGPP
6338     sprintf(eventName,"NCBevents[%d]", idx);
6339         NCBevents[idx] = thrd_CreateEvent(NULL, TRUE, FALSE, eventName);
6340     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6341         afsi_log("Event Object Already Exists: %s", eventName);
6342 #endif /* !DJGPP */
6343     sprintf(eventName,"NCBReturns[0<=i<smb_NumServerThreads][%d]", idx);
6344         retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6345     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6346         afsi_log("Event Object Already Exists: %s", eventName);
6347         for (i=0; i<smb_NumServerThreads; i++)
6348                 NCBreturns[i][idx] = retHandle;
6349         bufp = GetPacket();
6350         bufp->spacep = cm_GetSpace();
6351         bufs[idx] = bufp;
6352 }
6353
6354 /* listen for new connections */
6355 void smb_Listener(void *parmp)
6356 {
6357         NCB *ncbp;
6358     long code = 0;
6359     long len;
6360         long i, j;
6361     smb_vc_t *vcp;
6362         int flags = 0;
6363         char rname[NCBNAMSZ+1];
6364         char cname[MAX_COMPUTERNAME_LENGTH+1];
6365         int cnamelen = MAX_COMPUTERNAME_LENGTH+1;
6366 #ifdef DJGPP
6367     dos_ptr dos_ncb;
6368     time_t now;
6369 #endif /* DJGPP */
6370         int lana = (int) parmp;
6371
6372         ncbp = GetNCB();
6373 #ifdef DJGPP
6374     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6375 #endif /* DJGPP */
6376
6377     /* retrieve computer name */
6378     GetComputerName(cname, &cnamelen);
6379     _strupr(cname);
6380
6381         while (1) {
6382                 memset(ncbp, 0, sizeof(NCB));
6383                 flags = 0;
6384
6385 #ifndef NOEXPIRE
6386                 /* check for demo expiration */
6387                 {
6388                         unsigned long tod = time((void *) 0);
6389                         if (tod > EXPIREDATE) {
6390                                 (*smb_MBfunc)(NULL, "AFS demo expiration",
6391                                "afsd listener",
6392                                MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6393 #ifndef DJGPP
6394                 ExitThread(1);
6395 #else
6396                 thrd_Exit(1);
6397 #endif
6398                         }
6399                 }
6400 #endif /* !NOEXPIRE */
6401
6402         ncbp->ncb_command = NCBLISTEN;
6403         ncbp->ncb_rto = 0;      /* No receive timeout */
6404         ncbp->ncb_sto = 0;      /* No send timeout */
6405
6406                 /* pad out with spaces instead of null termination */
6407                 len = strlen(smb_localNamep);
6408         strncpy(ncbp->ncb_name, smb_localNamep, NCBNAMSZ);
6409         for(i=len; i<NCBNAMSZ; i++) ncbp->ncb_name[i] = ' ';
6410         
6411         strcpy(ncbp->ncb_callname, "*");
6412         for(i=1; i<NCBNAMSZ; i++) ncbp->ncb_callname[i] = ' ';
6413         
6414                 ncbp->ncb_lana_num = lana;
6415
6416 #ifndef DJGPP
6417         code = Netbios(ncbp);
6418 #else /* DJGPP */
6419         code = Netbios(ncbp, dos_ncb);
6420 #endif
6421
6422         if (code != 0)
6423         {
6424 #ifndef DJGPP
6425             char tbuffer[256];
6426 #endif
6427
6428             /* terminate silently if shutdown flag is set */
6429                 if (smbShutdownFlag == 1) {
6430 #ifndef DJGPP
6431                             ExitThread(1);
6432 #else
6433                                 thrd_Exit(1);
6434 #endif
6435                         }
6436
6437             osi_Log2(smb_logp, 
6438                      "NCBLISTEN lana=%d failed with code %d",
6439                      ncbp->ncb_lana_num, code);
6440             osi_Log0(smb_logp, 
6441                      "Client exiting due to network failure. Please restart client.\n");
6442
6443 #ifndef DJGPP
6444             sprintf(tbuffer, 
6445                      "Client exiting due to network failure.  Please restart client.\n"
6446                      "NCBLISTEN lana=%d failed with code %d",
6447                      ncbp->ncb_lana_num, code);
6448                         if (showErrors)
6449                 code = (*smb_MBfunc)(NULL, tbuffer, "AFS Client Service: Fatal Error",
6450                                      MB_OK|MB_SERVICE_NOTIFICATION);
6451             osi_assert(tbuffer);
6452             ExitThread(1);
6453 #else
6454             fprintf(stderr, "NCBLISTEN lana=%d failed with code %d\n",
6455                      ncbp->ncb_lana_num, code);
6456             fprintf(stderr, "\nClient exiting due to network failure "
6457                      "(possibly due to power-saving mode)\n");
6458             fprintf(stderr, "Please restart client.\n");
6459                         afs_exit(AFS_EXITCODE_NETWORK_FAILURE);
6460 #endif /* !DJGPP */
6461         }
6462
6463                 /* check for remote conns */
6464                 /* first get remote name and insert null terminator */
6465                 memcpy(rname, ncbp->ncb_callname, NCBNAMSZ);
6466                 for (i=NCBNAMSZ; i>0; i--) {
6467                         if (rname[i-1] != ' ' && rname[i-1] != 0) {
6468                                 rname[i] = 0;
6469                                 break;
6470                         }
6471                 }
6472
6473         /* compare with local name */
6474                 if (!isGateway)
6475                         if (strncmp(rname, cname, NCBNAMSZ) != 0)
6476                                 flags |= SMB_VCFLAG_REMOTECONN;
6477
6478                 osi_Log1(smb_logp, "New session lsn %d", ncbp->ncb_lsn);
6479                 /* lock */
6480                 lock_ObtainMutex(&smb_ListenerLock);
6481
6482                 /* New generation */
6483                 sessionGen++;
6484
6485                 /* Log session startup */
6486 #ifdef NOTSERVICE
6487         fprintf(stderr, "New session(ncb_lsn,ncb_lana_num) %d,%d starting from host "
6488                                 "%s\n",
6489                 ncbp->ncb_lsn,ncbp->ncb_lana_num, rname);
6490 #endif
6491         afsi_log("New session(ncb_lsn,ncb_lana_num) (%d,%d) starting from host %s, %d ongoing ops",
6492                   ncbp->ncb_lsn,ncbp->ncb_lana_num, rname, ongoingOps);
6493
6494         if (reportSessionStartups) {
6495 #ifndef DJGPP
6496                         HANDLE h;
6497                         char *ptbuf[1];
6498                         char s[100];
6499
6500                         h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
6501                         sprintf(s, "SMB session startup, %d ongoing ops", ongoingOps);
6502                         ptbuf[0] = s;
6503                         ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, 1004, NULL,
6504                         1, 0, ptbuf, NULL);
6505                         DeregisterEventSource(h);
6506 #else /* DJGPP */
6507             afsi_log("NCBLISTEN completed, call from %s",rname);
6508             osi_Log1(smb_logp, "SMB session startup, %d ongoing ops",
6509                      ongoingOps);
6510             time(&now);
6511             fprintf(stderr, "%s: New session %d starting from host %s\n",
6512                     asctime(localtime(&now)), ncbp->ncb_lsn, rname);
6513             fflush(stderr);
6514 #endif /* !DJGPP */
6515                 }
6516
6517         /* now ncbp->ncb_lsn is the connection ID */
6518         vcp = smb_FindVC(ncbp->ncb_lsn, SMB_FLAG_CREATE, ncbp->ncb_lana_num);
6519                 vcp->flags |= flags;
6520         strcpy(vcp->rname, rname);
6521
6522                 /* Allocate slot in session arrays */
6523                 /* Re-use dead session if possible, otherwise add one more */
6524         /* But don't look at session[0], it is reserved */
6525                 for (i = 1; i < numSessions; i++) {
6526                         if (dead_sessions[i]) {
6527                 afsi_log("connecting to dead session [ %d ]", i);
6528                                 dead_sessions[i] = FALSE;
6529                                 break;
6530                         }
6531                 }
6532
6533         /* assert that we do not exceed the maximum number of sessions or NCBs.
6534          * we should probably want to wait for a session to be freed in case
6535          * we run out.
6536          */
6537
6538         osi_assert(i < Sessionmax && numNCBs < NCBmax - 1);
6539
6540                 LSNs[i] = ncbp->ncb_lsn;
6541                 lanas[i] = ncbp->ncb_lana_num;
6542                 
6543                 if (i == numSessions) {
6544                         /* Add new NCB for new session */
6545             char eventName[MAX_PATH];
6546
6547             osi_Log1(smb_logp, "smb_Listener creating new session %d", i);
6548
6549                         InitNCBslot(numNCBs);
6550                         numNCBs++;
6551                         thrd_SetEvent(NCBavails[0]);
6552                         thrd_SetEvent(NCBevents[0]);
6553                         for (j = 0; j < smb_NumServerThreads; j++)
6554                                 thrd_SetEvent(NCBreturns[j][0]);
6555                         /* Also add new session event */
6556             sprintf(eventName, "SessionEvents[%d]", i);
6557             SessionEvents[i] = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
6558             if ( GetLastError() == ERROR_ALREADY_EXISTS )
6559                 afsi_log("Event Object Already Exists: %s", eventName);
6560                         numSessions++;
6561             afsi_log("increasing numNCBs [ %d ] numSessions [ %d ]", numNCBs, numSessions);
6562                         thrd_SetEvent(SessionEvents[0]);
6563                 } else {
6564                         thrd_SetEvent(SessionEvents[i]);
6565                 }
6566                 /* unlock */
6567                 lock_ReleaseMutex(&smb_ListenerLock);
6568
6569     }   /* dispatch while loop */
6570 }
6571
6572 /* initialize Netbios */
6573 void smb_NetbiosInit()
6574 {
6575     NCB *ncbp;
6576 #ifdef DJGPP
6577     dos_ptr dos_ncb;
6578 #endif /* DJGPP */
6579     int i, lana, code, l;
6580     char s[100];
6581     int delname_tried=0;
6582     int len;
6583     int lana_found = 0;
6584     OSVERSIONINFO Version;
6585
6586     /* AFAIK, this is the default for the ms loopback adapter.*/
6587     unsigned char kWLA_MAC[6] = { 0x02, 0x00, 0x4c, 0x4f, 0x4f, 0x50 };
6588     /*******************************************************************/
6589
6590     /* Get the version of Windows */
6591     memset(&Version, 0x00, sizeof(Version));
6592     Version.dwOSVersionInfoSize = sizeof(Version);
6593     GetVersionEx(&Version);
6594
6595     /* setup the NCB system */
6596     ncbp = GetNCB();
6597 #ifdef DJGPP
6598     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
6599 #endif /* DJGPP */
6600
6601 #ifndef DJGPP
6602     if (smb_LANadapter == -1) {
6603         ncbp->ncb_command = NCBENUM;
6604         ncbp->ncb_buffer = (PUCHAR)&lana_list;
6605         ncbp->ncb_length = sizeof(lana_list);
6606         code = Netbios(ncbp);
6607         if (code != 0) {
6608             sprintf(s, "Netbios NCBENUM error code %d", code);
6609             afsi_log(s);
6610             osi_panic(s, __FILE__, __LINE__);
6611         }
6612     }
6613     else {
6614         lana_list.length = 1;
6615         lana_list.lana[0] = smb_LANadapter;
6616     }
6617           
6618     for (i = 0; i < lana_list.length; i++) {
6619         /* reset the adaptor: in Win32, this is required for every process, and
6620          * acts as an init call, not as a real hardware reset.
6621          */
6622         ncbp->ncb_command = NCBRESET;
6623         ncbp->ncb_callname[0] = 100;
6624         ncbp->ncb_callname[2] = 100;
6625         ncbp->ncb_lana_num = lana_list.lana[i];
6626         code = Netbios(ncbp);
6627         if (code == 0) 
6628             code = ncbp->ncb_retcode;
6629         if (code != 0) {
6630             sprintf(s, "Netbios NCBRESET lana %d error code %d", lana_list.lana[i], code);
6631             afsi_log(s);
6632             lana_list.lana[i] = 255;  /* invalid lana */
6633         } else {
6634             sprintf(s, "Netbios NCBRESET lana %d succeeded", lana_list.lana[i]);
6635             afsi_log(s);
6636         }
6637     }
6638 #else
6639     /* for DJGPP, there is no NCBENUM and NCBRESET is a real reset.  so
6640        we will just fake the LANA list */
6641     if (smb_LANadapter == -1) {
6642         for (i = 0; i < 8; i++)
6643             lana_list.lana[i] = i;
6644         lana_list.length = 8;
6645     }
6646     else {
6647         lana_list.length = 1;
6648         lana_list.lana[0] = smb_LANadapter;
6649     }
6650 #endif /* !DJGPP */
6651
6652     /* and declare our name so we can receive connections */
6653     memset(ncbp, 0, sizeof(*ncbp));
6654     len=lstrlen(smb_localNamep);
6655     memset(smb_sharename,' ',NCBNAMSZ);
6656     memcpy(smb_sharename,smb_localNamep,len);
6657     sprintf(s, "lana_list.length %d", lana_list.length);
6658     afsi_log(s);
6659
6660     /* Keep the name so we can unregister it later */
6661     for (l = 0; l < lana_list.length; l++) {
6662         lana = lana_list.lana[l];
6663
6664         ncbp->ncb_command = NCBADDNAME;
6665         ncbp->ncb_lana_num = lana;
6666         memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6667 #ifndef DJGPP
6668         code = Netbios(ncbp);
6669 #else /* DJGPP */
6670         code = Netbios(ncbp, dos_ncb);
6671 #endif /* !DJGPP */
6672           
6673         afsi_log("Netbios NCBADDNAME lana=%d code=%d retcode=%d complete=%d",
6674                  lana, code, ncbp->ncb_retcode,ncbp->ncb_cmd_cplt);
6675         {
6676             char name[NCBNAMSZ+1];
6677             name[NCBNAMSZ]=0;
6678             memcpy(name,ncbp->ncb_name,NCBNAMSZ);
6679             afsi_log("Netbios NCBADDNAME added new name >%s<",name);
6680         }
6681
6682         if (code == 0) code = ncbp->ncb_retcode;
6683         if (code == 0) {
6684             afsi_log("Netbios NCBADDNAME succeeded on lana %d\n", lana);
6685 #ifdef DJGPP
6686             /* we only use one LANA with djgpp */
6687             lana_list.lana[0] = lana;
6688             lana_list.length = 1;
6689 #endif    
6690         }
6691         else {
6692             sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6693             afsi_log(s);
6694             if (code == NRC_BRIDGE) {    /* invalid LANA num */
6695                 lana_list.lana[l] = 255;
6696                 continue;
6697             }
6698             else if (code == NRC_DUPNAME) {
6699                 afsi_log("Name already exists; try to delete it");
6700                 memset(ncbp, 0, sizeof(*ncbp));
6701                 ncbp->ncb_command = NCBDELNAME;
6702                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
6703                 ncbp->ncb_lana_num = lana;
6704 #ifndef DJGPP
6705                 code = Netbios(ncbp);
6706 #else
6707                 code = Netbios(ncbp, dos_ncb);
6708 #endif /* DJGPP */
6709                 if (code == 0) code = ncbp->ncb_retcode;
6710                 else {
6711                     sprintf(s, "Netbios NCBDELNAME lana %d error code %d\n", lana, code);
6712                     afsi_log(s);
6713                 }
6714                 if (code != 0 || delname_tried) {
6715                     lana_list.lana[l] = 255;
6716                 }
6717                 else if (code == 0) {
6718                     if (!delname_tried) {
6719                         lana--;
6720                         delname_tried = 1;
6721                         continue;
6722                     }
6723                 }
6724             }
6725             else {
6726                 sprintf(s, "Netbios NCBADDNAME lana %d error code %d", lana, code);
6727                 afsi_log(s);
6728                 lana_list.lana[l] = 255;  /* invalid lana */
6729                 osi_panic(s, __FILE__, __LINE__);
6730             }
6731         }
6732         if (code == 0) {
6733             lana_found = 1;   /* at least one worked */
6734 #ifdef DJGPP
6735             break;
6736 #endif
6737         }
6738     }
6739
6740     osi_assert(lana_list.length >= 0);
6741     if (!lana_found) {
6742         sprintf(s, "No valid LANA numbers found!");
6743         osi_panic(s, __FILE__, __LINE__);
6744     }
6745         
6746     /* we're done with the NCB now */
6747     FreeNCB(ncbp);
6748 }
6749
6750 void smb_Init(osi_log_t *logp, char *snamep, int useV3, int LANadapt,
6751               int nThreads
6752 #ifndef DJGPP
6753               , void *aMBfunc
6754 #endif
6755   )
6756
6757 {
6758         thread_t phandle;
6759     int lpid;
6760     int i;
6761     int len;
6762         struct tm myTime;
6763 #ifdef DJGPP
6764     int npar, seg, sel;
6765     dos_ptr rawBuf;
6766 #endif /* DJGPP */
6767     EVENT_HANDLE retHandle;
6768     char eventName[MAX_PATH];
6769
6770 #ifndef DJGPP
6771         smb_MBfunc = aMBfunc;
6772 #endif /* DJGPP */
6773
6774 #ifndef NOEXPIRE
6775         /* check for demo expiration */
6776         {
6777                 unsigned long tod = time((void *) 0);
6778                 if (tod > EXPIREDATE) {
6779 #ifndef DJGPP
6780                         (*smb_MBfunc)(NULL, "AFS demo expiration", "afsd",
6781                           MB_OK|MB_ICONSTOP|MB_SETFOREGROUND|MB_SERVICE_NOTIFICATION);
6782                         exit(1);
6783 #else /* DJGPP */
6784             fprintf(stderr, "AFS demo expiration\n");
6785             afs_exit(0);
6786 #endif /* !DJGPP */
6787                 }
6788         }
6789 #endif /* !NOEXPIRE */
6790
6791         smb_useV3 = useV3;
6792         smb_LANadapter = LANadapt;
6793
6794         /* Initialize smb_localZero */
6795         myTime.tm_isdst = -1;           /* compute whether on DST or not */
6796         myTime.tm_year = 70;
6797         myTime.tm_mon = 0;
6798         myTime.tm_mday = 1;
6799         myTime.tm_hour = 0;
6800         myTime.tm_min = 0;
6801         myTime.tm_sec = 0;
6802         smb_localZero = mktime(&myTime);
6803
6804         /* Initialize kludge-GMT */
6805         smb_CalculateNowTZ();
6806
6807         /* initialize the remote debugging log */
6808         smb_logp = logp;
6809         
6810     /* remember the name */
6811         len = strlen(snamep);
6812     smb_localNamep = malloc(len+1);
6813     strcpy(smb_localNamep, snamep);
6814     afsi_log("smb_localNamep is >%s<", smb_localNamep);
6815
6816         /* and the global lock */
6817     lock_InitializeRWLock(&smb_globalLock, "smb global lock");
6818     lock_InitializeRWLock(&smb_rctLock, "smb refct and tree struct lock");
6819
6820         /* Raw I/O data structures */
6821         lock_InitializeMutex(&smb_RawBufLock, "smb raw buffer lock");
6822
6823         lock_InitializeMutex(&smb_ListenerLock, "smb listener lock");
6824         
6825         /* 4 Raw I/O buffers */
6826 #ifndef DJGPP
6827         smb_RawBufs = calloc(65536,1);
6828         *((char **)smb_RawBufs) = NULL;
6829         for (i=0; i<3; i++) {
6830                 char *rawBuf = calloc(65536,1);
6831                 *((char **)rawBuf) = smb_RawBufs;
6832                 smb_RawBufs = rawBuf;
6833         }
6834 #else /* DJGPP */
6835     npar = 65536 >> 4;  /* number of paragraphs */
6836     seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[0]);
6837     if (seg == -1) {
6838         afsi_log("Cannot allocate %d paragraphs of DOS memory",
6839                   npar);
6840         osi_panic("",__FILE__,__LINE__);
6841     }
6842     else {
6843         afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6844                   npar, seg);
6845     }
6846     smb_RawBufs = (seg * 16) + 0;  /* DOS physical address */
6847         
6848     _farpokel(_dos_ds, smb_RawBufs, NULL);
6849     for (i=0; i<SMB_RAW_BUFS-1; i++) {
6850         npar = 65536 >> 4;  /* number of paragraphs */
6851         seg = __dpmi_allocate_dos_memory(npar, &smb_RawBufSel[i+1]);
6852         if (seg == -1) {
6853             afsi_log("Cannot allocate %d paragraphs of DOS memory",
6854                       npar);
6855             osi_panic("",__FILE__,__LINE__);
6856         }
6857         else {
6858             afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
6859                       npar, seg);
6860         }
6861         rawBuf = (seg * 16) + 0;  /* DOS physical address */
6862         /*_farpokel(_dos_ds, smb_RawBufs, smb_RawBufs);*/
6863         _farpokel(_dos_ds, rawBuf, smb_RawBufs);
6864         smb_RawBufs = rawBuf;
6865     }
6866 #endif /* !DJGPP */
6867
6868         /* global free lists */
6869         smb_ncbFreeListp = NULL;
6870     smb_packetFreeListp = NULL;
6871
6872     smb_NetbiosInit();
6873
6874         /* Initialize listener and server structures */
6875         memset(dead_sessions, 0, sizeof(dead_sessions));
6876     sprintf(eventName, "SessionEvents[0]");
6877         SessionEvents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6878     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6879         afsi_log("Event Object Already Exists: %s", eventName);
6880         numSessions = 1;
6881         smb_NumServerThreads = nThreads;
6882     sprintf(eventName, "NCBavails[0]");
6883         NCBavails[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6884     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6885         afsi_log("Event Object Already Exists: %s", eventName);
6886     sprintf(eventName, "NCBevents[0]");
6887         NCBevents[0] = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6888     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6889         afsi_log("Event Object Already Exists: %s", eventName);
6890         NCBreturns = malloc(nThreads * sizeof(EVENT_HANDLE *));
6891     sprintf(eventName, "NCBreturns[0<=i<smb_NumServerThreads][0]");
6892     retHandle = thrd_CreateEvent(NULL, FALSE, FALSE, eventName);
6893     if ( GetLastError() == ERROR_ALREADY_EXISTS )
6894         afsi_log("Event Object Already Exists: %s", eventName);
6895         for (i = 0; i < smb_NumServerThreads; i++) {
6896                 NCBreturns[i] = malloc(NCBmax * sizeof(EVENT_HANDLE));
6897                 NCBreturns[i][0] = retHandle;
6898         }
6899         for (i = 1; i <= nThreads; i++)
6900                 InitNCBslot(i);
6901         numNCBs = nThreads + 1;
6902
6903         /* Initialize dispatch table */
6904         memset(&smb_dispatchTable, 0, sizeof(smb_dispatchTable));
6905         smb_dispatchTable[0x00].procp = smb_ReceiveCoreMakeDir;
6906         smb_dispatchTable[0x01].procp = smb_ReceiveCoreRemoveDir;
6907         smb_dispatchTable[0x02].procp = smb_ReceiveCoreOpen;
6908         smb_dispatchTable[0x03].procp = smb_ReceiveCoreCreate;
6909         smb_dispatchTable[0x04].procp = smb_ReceiveCoreClose;
6910         smb_dispatchTable[0x05].procp = smb_ReceiveCoreFlush;
6911         smb_dispatchTable[0x06].procp = smb_ReceiveCoreUnlink;
6912         smb_dispatchTable[0x07].procp = smb_ReceiveCoreRename;
6913         smb_dispatchTable[0x08].procp = smb_ReceiveCoreGetFileAttributes;
6914         smb_dispatchTable[0x09].procp = smb_ReceiveCoreSetFileAttributes;
6915         smb_dispatchTable[0x0a].procp = smb_ReceiveCoreRead;
6916         smb_dispatchTable[0x0b].procp = smb_ReceiveCoreWrite;
6917         smb_dispatchTable[0x0c].procp = smb_ReceiveCoreLockRecord;
6918         smb_dispatchTable[0x0d].procp = smb_ReceiveCoreUnlockRecord;
6919         smb_dispatchTable[0x0e].procp = smb_SendCoreBadOp; /* create temporary */
6920         smb_dispatchTable[0x0f].procp = smb_ReceiveCoreCreate;
6921         smb_dispatchTable[0x10].procp = smb_ReceiveCoreCheckPath;
6922         smb_dispatchTable[0x11].procp = smb_SendCoreBadOp;      /* process exit */
6923         smb_dispatchTable[0x12].procp = smb_ReceiveCoreSeek;
6924         smb_dispatchTable[0x1a].procp = smb_ReceiveCoreReadRaw;
6925         /* Set NORESPONSE because smb_ReceiveCoreReadRaw() does the responses itself */
6926         smb_dispatchTable[0x1a].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6927         smb_dispatchTable[0x1d].procp = smb_ReceiveCoreWriteRawDummy;
6928         smb_dispatchTable[0x22].procp = smb_ReceiveV3SetAttributes;
6929         smb_dispatchTable[0x23].procp = smb_ReceiveV3GetAttributes;
6930         smb_dispatchTable[0x24].procp = smb_ReceiveV3LockingX;
6931         smb_dispatchTable[0x24].flags |= SMB_DISPATCHFLAG_CHAINED;
6932         smb_dispatchTable[0x29].procp = smb_SendCoreBadOp;      /* copy file */
6933         smb_dispatchTable[0x2b].procp = smb_ReceiveCoreEcho;
6934         /* Set NORESPONSE because smb_ReceiveCoreEcho() does the responses itself */
6935         smb_dispatchTable[0x2b].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6936     smb_dispatchTable[0x2d].procp = smb_ReceiveV3OpenX;
6937     smb_dispatchTable[0x2d].flags |= SMB_DISPATCHFLAG_CHAINED;
6938     smb_dispatchTable[0x2e].procp = smb_ReceiveV3ReadX;
6939     smb_dispatchTable[0x2e].flags |= SMB_DISPATCHFLAG_CHAINED;
6940         smb_dispatchTable[0x32].procp = smb_ReceiveV3Tran2A;    /* both are same */
6941     smb_dispatchTable[0x32].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6942     smb_dispatchTable[0x33].procp = smb_ReceiveV3Tran2A;
6943     smb_dispatchTable[0x33].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6944     smb_dispatchTable[0x34].procp = smb_ReceiveV3FindClose;
6945     smb_dispatchTable[0x35].procp = smb_ReceiveV3FindNotifyClose;
6946         smb_dispatchTable[0x70].procp = smb_ReceiveCoreTreeConnect;
6947         smb_dispatchTable[0x71].procp = smb_ReceiveCoreTreeDisconnect;
6948         smb_dispatchTable[0x72].procp = smb_ReceiveNegotiate;
6949         smb_dispatchTable[0x73].procp = smb_ReceiveV3SessionSetupX;
6950     smb_dispatchTable[0x73].flags |= SMB_DISPATCHFLAG_CHAINED;
6951     smb_dispatchTable[0x74].procp = smb_ReceiveV3UserLogoffX;
6952     smb_dispatchTable[0x74].flags |= SMB_DISPATCHFLAG_CHAINED;
6953     smb_dispatchTable[0x75].procp = smb_ReceiveV3TreeConnectX;
6954     smb_dispatchTable[0x75].flags |= SMB_DISPATCHFLAG_CHAINED;
6955         smb_dispatchTable[0x80].procp = smb_ReceiveCoreGetDiskAttributes;
6956         smb_dispatchTable[0x81].procp = smb_ReceiveCoreSearchDir;
6957         smb_dispatchTable[0xA0].procp = smb_ReceiveNTTransact;
6958         smb_dispatchTable[0xA2].procp = smb_ReceiveNTCreateX;
6959         smb_dispatchTable[0xA2].flags |= SMB_DISPATCHFLAG_CHAINED;
6960         smb_dispatchTable[0xA4].procp = smb_ReceiveNTCancel;
6961         smb_dispatchTable[0xA4].flags |= SMB_DISPATCHFLAG_NORESPONSE;
6962         smb_dispatchTable[0xc0].procp = smb_SendCoreBadOp;
6963         smb_dispatchTable[0xc1].procp = smb_SendCoreBadOp;
6964         smb_dispatchTable[0xc2].procp = smb_SendCoreBadOp;
6965         smb_dispatchTable[0xc3].procp = smb_SendCoreBadOp;
6966         for(i=0xd0; i<= 0xd7; i++) {
6967                 smb_dispatchTable[i].procp = smb_SendCoreBadOp;
6968     }
6969
6970         /* setup tran 2 dispatch table */
6971         smb_tran2DispatchTable[0].procp = smb_ReceiveTran2Open;
6972         smb_tran2DispatchTable[1].procp = smb_ReceiveTran2SearchDir;    /* FindFirst */
6973         smb_tran2DispatchTable[2].procp = smb_ReceiveTran2SearchDir;    /* FindNext */
6974         smb_tran2DispatchTable[3].procp = smb_ReceiveTran2QFSInfo;
6975         smb_tran2DispatchTable[4].procp = smb_ReceiveTran2SetFSInfo;
6976         smb_tran2DispatchTable[5].procp = smb_ReceiveTran2QPathInfo;
6977         smb_tran2DispatchTable[6].procp = smb_ReceiveTran2SetPathInfo;
6978         smb_tran2DispatchTable[7].procp = smb_ReceiveTran2QFileInfo;
6979         smb_tran2DispatchTable[8].procp = smb_ReceiveTran2SetFileInfo;
6980         smb_tran2DispatchTable[9].procp = smb_ReceiveTran2FSCTL;
6981         smb_tran2DispatchTable[10].procp = smb_ReceiveTran2IOCTL;
6982         smb_tran2DispatchTable[11].procp = smb_ReceiveTran2FindNotifyFirst;
6983         smb_tran2DispatchTable[12].procp = smb_ReceiveTran2FindNotifyNext;
6984         smb_tran2DispatchTable[13].procp = smb_ReceiveTran2MKDir;
6985
6986         smb3_Init();
6987
6988         /* Start listeners, waiters, servers, and daemons */
6989
6990         for (i = 0; i < lana_list.length; i++) {
6991                 if (lana_list.lana[i] == 255) continue;
6992                 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Listener,
6993                         (void*)lana_list.lana[i], 0, &lpid, "smb_Listener");
6994                 osi_assert(phandle != NULL);
6995                 thrd_CloseHandle(phandle);
6996         }
6997
6998 #ifndef DJGPP
6999     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ClientWaiter,
7000                           NULL, 0, &lpid, "smb_ClientWaiter");
7001         osi_assert(phandle != NULL);
7002         thrd_CloseHandle(phandle);
7003 #endif /* !DJGPP */
7004
7005     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_ServerWaiter,
7006                           NULL, 0, &lpid, "smb_ServerWaiter");
7007         osi_assert(phandle != NULL);
7008         thrd_CloseHandle(phandle);
7009
7010         for (i=0; i<nThreads; i++) {
7011                 phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Server,
7012                               (void *) i, 0, &lpid, "smb_Server");
7013                 osi_assert(phandle != NULL);
7014                 thrd_CloseHandle(phandle);
7015         }
7016
7017     phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_Daemon,
7018                           NULL, 0, &lpid, "smb_Daemon");
7019         osi_assert(phandle != NULL);
7020         thrd_CloseHandle(phandle);
7021
7022         phandle = thrd_Create(NULL, 65536, (ThreadFunc) smb_WaitingLocksDaemon,
7023                           NULL, 0, &lpid, "smb_WaitingLocksDaemon");
7024         osi_assert(phandle != NULL);
7025         thrd_CloseHandle(phandle);
7026
7027 #ifdef DJGPP
7028         smb_ListShares();
7029 #endif
7030
7031         return;
7032 }
7033
7034 void smb_Shutdown(void)
7035 {
7036     NCB *ncbp;
7037 #ifdef DJGPP
7038     dos_ptr dos_ncb;
7039 #endif
7040     long code = 0;
7041     int i;
7042
7043     /*fprintf(stderr, "Entering smb_Shutdown\n");*/
7044         
7045     /* setup the NCB system */
7046     ncbp = GetNCB();
7047 #ifdef DJGPP
7048     dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
7049 #endif
7050
7051     /* Block new sessions by setting shutdown flag */
7052     smbShutdownFlag = 1;
7053
7054     /* Hang up all sessions */
7055     memset((char *)ncbp, 0, sizeof(NCB));
7056     for (i = 1; i < numSessions; i++)
7057     {
7058         if (dead_sessions[i])
7059             continue;
7060       
7061         /*fprintf(stderr, "NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7062         ncbp->ncb_command = NCBHANGUP;
7063         ncbp->ncb_lana_num = lanas[i];  /*smb_LANadapter;*/
7064         ncbp->ncb_lsn = LSNs[i];
7065 #ifndef DJGPP
7066         code = Netbios(ncbp);
7067 #else
7068                 code = Netbios(ncbp, dos_ncb);
7069 #endif
7070         /*fprintf(stderr, "returned from NCBHANGUP session %d LSN %d\n", i, LSNs[i]);*/
7071         if (code == 0) code = ncbp->ncb_retcode;
7072         if (code != 0) {
7073             osi_Log1(smb_logp, "Netbios NCBHANGUP error code %d", code);
7074             fprintf(stderr, "Session %d Netbios NCBHANGUP error code %d", i, code);
7075         }
7076     }
7077
7078     /* Delete Netbios name */
7079     memset((char *)ncbp, 0, sizeof(NCB));
7080         for (i = 0; i < lana_list.length; i++) {
7081                 if (lana_list.lana[i] == 255) continue;
7082                 ncbp->ncb_command = NCBDELNAME;
7083                 ncbp->ncb_lana_num = lana_list.lana[i];
7084                 memcpy(ncbp->ncb_name,smb_sharename,NCBNAMSZ);
7085 #ifndef DJGPP
7086         code = Netbios(ncbp);
7087 #else
7088                 code = Netbios(ncbp, dos_ncb);
7089 #endif
7090                 if (code == 0) code = ncbp->ncb_retcode;
7091                 if (code != 0) {
7092                         fprintf(stderr, "Netbios NCBDELNAME lana %d error code %d",
7093                         ncbp->ncb_lana_num, code);
7094                 }
7095                 fflush(stderr);
7096         }
7097 }
7098
7099 /* Get the UNC \\<servername>\<sharename> prefix. */
7100 char *smb_GetSharename()
7101 {
7102     char *name;
7103
7104         /* Make sure we have been properly initialized. */
7105         if (smb_localNamep == NULL)
7106                 return NULL;
7107
7108     /* Allocate space for \\<servername>\<sharename>, plus the
7109      * terminator.
7110      */
7111     name = malloc(strlen(smb_localNamep) + strlen("ALL") + 4);
7112     sprintf(name, "\\\\%s\\%s", smb_localNamep, "ALL");
7113     return name;
7114 }   
7115
7116 #ifdef NOTSERVICE
7117
7118 void smb_LogPacket(smb_packet_t *packet)
7119 {
7120         BYTE *vp, *cp;
7121         unsigned length, paramlen, datalen, i, j;
7122         char buf[81];
7123         char hex[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
7124
7125         if(!packet) return;
7126
7127         osi_Log0(smb_logp, "*** SMB packet dump ***");
7128
7129         vp = (BYTE *) packet->data;
7130
7131         datalen = *((WORD*)(vp + (paramlen = ((unsigned)*(vp+20)) << 1)));
7132         length = paramlen + 2 + datalen;
7133
7134
7135         for(i=0;i < length; i+=16)
7136         {
7137                 memset( buf, ' ', 80 );
7138                 buf[80] = 0;
7139
7140                 itoa( i, buf, 16 );
7141
7142                 buf[strlen(buf)] = ' ';
7143
7144                 cp = (BYTE*) buf + 7;
7145
7146                 for(j=0;j < 16 && (i+j)<length; j++)
7147                 {
7148                         *(cp++) = hex[vp[i+j] >> 4];
7149                         *(cp++) = hex[vp[i+j] & 0xf];
7150                         *(cp++) = ' ';
7151
7152                         if(j==7)
7153                         {
7154                                 *(cp++) = '-';
7155                                 *(cp++) = ' ';
7156                         }
7157                 }
7158
7159                 for(j=0;j < 16 && (i+j)<length;j++)
7160                 {
7161                         *(cp++) = ( 32 <= vp[i+j] && 128 > vp[i+j] )? vp[i+j]:'.';
7162                         if(j==7)
7163                         {
7164                                 *(cp++) = ' ';
7165                                 *(cp++) = '-';
7166                                 *(cp++) = ' ';
7167                         }
7168                 }
7169
7170                 *cp = 0;
7171
7172                 osi_Log0( smb_logp, buf );
7173         }
7174
7175         osi_Log0(smb_logp, "*** End SMB packet dump ***");
7176
7177 }
7178
7179 #endif /* NOTSERVICE */
7180
7181 int smb_DumpVCP(FILE *outputFile, char *cookie)
7182 {
7183     int zilch;
7184     char output[1024];
7185   
7186     smb_vc_t *vcp;
7187   
7188     lock_ObtainRead(&smb_rctLock);
7189   
7190     for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) 
7191     {
7192         smb_fid_t *fidp;
7193       
7194         sprintf(output, "%s vcp=0x%08X, refCount=%d, flags=%d, vcID=%d, lsn=%d, uidCounter=%d, tidCounter=%d, fidCounter=%d\n",
7195                  cookie, vcp, vcp->refCount, vcp->flags, vcp->vcID, vcp->lsn, vcp->uidCounter, vcp->tidCounter, vcp->fidCounter);
7196         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7197       
7198         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) 
7199         {
7200             sprintf(output, "%s -- fidp=0x%08X, refCount=%d, fid=%d, vcp=0x%08X, scp=0x%08X, ioctlp=0x%08X, NTopen_pathp=%s, NTopen_wholepathp=%s\n", 
7201                      cookie, fidp, fidp->refCount, fidp->fid, fidp->vcp, fidp->scp, fidp->ioctlp, 
7202                      fidp->NTopen_pathp ? fidp->NTopen_pathp : "NULL", 
7203                      fidp->NTopen_wholepathp ? fidp->NTopen_wholepathp : "NULL");
7204             WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7205         }
7206       
7207         sprintf(output, "done dumping fidsp\n");
7208         WriteFile(outputFile, output, strlen(output), &zilch, NULL);
7209     }       
7210   
7211     lock_ReleaseRead(&smb_rctLock);
7212     return 0;
7213 }