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