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