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