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