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