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