win32-name-event-objects-20040228
[openafs.git] / src / WINNT / afsd / smb.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 //#define NOSERVICE 1
11
12 #define NOMOREFILESFIX 1
13
14 #include <afs/param.h>
15 #include <afs/stds.h>
16
17 #ifndef DJGPP
18 #include <windows.h>
19 #else
20 #include <sys/timeb.h>
21 #include <tzfile.h>
22 #endif /* !DJGPP */
23 #include <stddef.h>
24 #include <stdlib.h>
25 #include <malloc.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <time.h>
29
30 #include <osi.h>
31
32 #include "afsd.h"
33
34 #include "smb.h"
35 #include "lanahelper.h"
36
37 /* These characters are illegal in Windows filenames */
38 static char *illegalChars = "\\/:*?\"<>|";
39 BOOL isWindows2000 = FALSE;
40
41 smb_vc_t *dead_vcp = NULL;
42 smb_vc_t *active_vcp = NULL;
43
44 /* TODO; logout mechanism needs to be thread-safe */
45 char *loggedOutName = NULL;
46 smb_user_t *loggedOutUserp = NULL;
47 unsigned long loggedOutTime;
48 int loggedOut = 0;
49 #ifdef DJGPP
50 int smbShutdownFlag = 0;
51 #endif /* DJGPP */
52
53 int smb_LogoffTokenTransfer;
54 unsigned long smb_LogoffTransferTimeout;
55
56 DWORD last_msg_time = 0;
57
58 long ongoingOps = 0;
59
60 unsigned int sessionGen = 0;
61
62 extern void afsi_log(char *pattern, ...);
63 extern HANDLE afsi_file;
64
65 osi_hyper_t hzero = {0, 0};
66 osi_hyper_t hones = {0xFFFFFFFF, -1};
67
68 osi_log_t *  smb_logp;
69 osi_rwlock_t smb_globalLock;
70 osi_rwlock_t smb_rctLock;
71 osi_mutex_t  smb_ListenerLock;
72  
73 char smb_LANadapter;
74 unsigned char smb_sharename[NCBNAMSZ+1] = {0};
75
76 /* for debugging */
77 long smb_maxObsConcurrentCalls=0;
78 long smb_concurrentCalls=0;
79
80 smb_dispatch_t smb_dispatchTable[SMB_NOPCODES];
81
82 smb_packet_t *smb_packetFreeListp;
83 smb_ncb_t *smb_ncbFreeListp;
84
85 int smb_NumServerThreads;
86
87 int numNCBs, numSessions;
88
89 int smb_maxVCPerServer;
90 int smb_maxMpxRequests;
91
92 #define NCBmax MAXIMUM_WAIT_OBJECTS
93 EVENT_HANDLE NCBavails[NCBmax], NCBevents[NCBmax];
94 EVENT_HANDLE **NCBreturns;
95 DWORD NCBsessions[NCBmax];
96 NCB *NCBs[NCBmax];
97 struct smb_packet *bufs[NCBmax];
98
99 #define Sessionmax MAXIMUM_WAIT_OBJECTS
100 EVENT_HANDLE SessionEvents[Sessionmax];
101 unsigned short LSNs[Sessionmax];
102 int lanas[Sessionmax];
103 BOOL dead_sessions[Sessionmax];
104 LANA_ENUM lana_list;
105
106 /* for raw I/O */
107 osi_mutex_t smb_RawBufLock;
108 #ifdef DJGPP
109 #define SMB_RAW_BUFS 4
110 dos_ptr smb_RawBufs;
111 int smb_RawBufSel[SMB_RAW_BUFS];
112 #else
113 char *smb_RawBufs;
114 #endif /* DJGPP */
115
116 #define RAWTIMEOUT INFINITE
117
118 /* for raw write */
119 typedef struct raw_write_cont {
120         long code;
121         osi_hyper_t offset;
122         long count;
123 #ifndef DJGPP
124         char *buf;
125 #else
126         dos_ptr buf;
127 #endif /* DJGPP */
128         int writeMode;
129         long alreadyWritten;
130 } raw_write_cont_t;
131
132 /* dir search stuff */
133 long smb_dirSearchCounter = 1;
134 smb_dirSearch_t *smb_firstDirSearchp;
135 smb_dirSearch_t *smb_lastDirSearchp;
136
137 /* hide dot files? */
138 int smb_hideDotFiles;
139
140 /* global state about V3 protocols */
141 int smb_useV3;          /* try to negotiate V3 */
142
143 #ifndef DJGPP
144 /* MessageBox or something like it */
145 int (WINAPI *smb_MBfunc)(HWND, LPCTSTR, LPCTSTR, UINT) = NULL;
146 #endif /* DJGPP */
147
148 /* GMT time info:
149  * Time in Unix format of midnight, 1/1/1970 local time.
150  * When added to dosUTime, gives Unix (AFS) time.
151  */
152 long smb_localZero;
153
154 /* Time difference for converting to kludge-GMT */
155 int smb_NowTZ;
156
157 char *smb_localNamep = NULL;
158
159 smb_vc_t *smb_allVCsp;
160
161 smb_username_t *usernamesp = NULL;
162
163 smb_waitingLock_t *smb_allWaitingLocks;
164
165 /* forward decl */
166 void smb_DispatchPacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp,
167         NCB *ncbp, raw_write_cont_t *rwcp);
168 void smb_NetbiosInit();
169 #ifdef DJGPP
170 #ifndef AFS_WIN95_ENV
171 DWORD smb_ServerExceptionFilter(void);
172 #endif
173
174 extern char cm_HostName[];
175 extern char cm_confDir[];
176 #endif
177
178 #ifdef DJGPP
179 #define LPTSTR char *
180 #define GetComputerName(str, sizep) \
181        strcpy((str), cm_HostName); \
182        *(sizep) = strlen(cm_HostName)
183 #endif /* DJGPP */
184
185 extern char AFSConfigKeyName[];
186
187 /*
188  * Demo expiration
189  *
190  * To build an expiring version, comment out the definition of NOEXPIRE,
191  * and set the definition of EXPIREDATE to the desired value.
192  */
193 #define NOEXPIRE 1
194 #define EXPIREDATE 834000000            /* Wed Jun 5 1996 */
195
196
197 char * myCrt_Dispatch(int i)
198 {
199         switch (i)
200         {
201         default:
202                 return "unknown SMB op";
203         case 0x00:
204                 return "(00)ReceiveCoreMakeDir";
205         case 0x01:
206                 return "(01)ReceiveCoreRemoveDir";
207         case 0x02:
208                 return "(02)ReceiveCoreOpen";
209         case 0x03:
210                 return "(03)ReceiveCoreCreate";
211         case 0x04:
212                 return "(04)ReceiveCoreClose";
213         case 0x05:
214                 return "(05)ReceiveCoreFlush";
215         case 0x06:
216                 return "(06)ReceiveCoreUnlink";
217         case 0x07:
218                 return "(07)ReceiveCoreRename";
219         case 0x08:
220                 return "(08)ReceiveCoreGetFileAttributes";
221         case 0x09:
222                 return "(09)ReceiveCoreSetFileAttributes";
223         case 0x0a:
224                 return "(0a)ReceiveCoreRead";
225         case 0x0b:
226                 return "(0b)ReceiveCoreWrite";
227         case 0x0c:
228                 return "(0c)ReceiveCoreLockRecord";
229         case 0x0d:
230                 return "(0d)ReceiveCoreUnlockRecord";
231         case 0x0e:
232                 return "(0e)SendCoreBadOp";
233         case 0x0f:
234                 return "(0f)ReceiveCoreCreate";
235         case 0x10:
236                 return "(10)ReceiveCoreCheckPath";
237         case 0x11:
238                 return "(11)SendCoreBadOp";
239         case 0x12:
240                 return "(12)ReceiveCoreSeek";
241         case 0x1a:
242                 return "(1a)ReceiveCoreReadRaw";
243         case 0x1d:
244                 return "(1d)ReceiveCoreWriteRawDummy";
245         case 0x22:
246                 return "(22)ReceiveV3SetAttributes";
247         case 0x23:
248                 return "(23)ReceiveV3GetAttributes";
249         case 0x24:
250                 return "(24)ReceiveV3LockingX";
251         case 0x29:
252                 return "(29)SendCoreBadOp";
253         case 0x2b:
254                 return "(2b)ReceiveCoreEcho";
255         case 0x2d:
256                 return "(2d)ReceiveV3OpenX";
257         case 0x2e:
258                 return "(2e)ReceiveV3ReadX";
259         case 0x32:
260                 return "(32)ReceiveV3Tran2A";
261         case 0x33:
262                 return "(33)ReceiveV3Tran2A";
263         case 0x34:
264                 return "(34)ReceiveV3FindClose";
265         case 0x35:
266                 return "(35)ReceiveV3FindNotifyClose";
267         case 0x70:
268                 return "(70)ReceiveCoreTreeConnect";
269         case 0x71:
270                 return "(71)ReceiveCoreTreeDisconnect";
271         case 0x72:
272                 return "(72)ReceiveNegotiate";
273         case 0x73:
274                 return "(73)ReceiveV3SessionSetupX";
275         case 0x74:
276                 return "(74)ReceiveV3UserLogoffX";
277         case 0x75:
278                 return "(75)ReceiveV3TreeConnectX";
279         case 0x80:
280                 return "(80)ReceiveCoreGetDiskAttributes";
281         case 0x81:
282                 return "(81)ReceiveCoreSearchDir";
283         case 0xA0:
284                 return "(A0)ReceiveNTTransact";
285         case 0xA2:
286                 return "(A2)ReceiveNTCreateX";
287         case 0xA4:
288                 return "(A4)ReceiveNTCancel";
289         case 0xc0:
290                 return "(c0)SendCoreBadOp";
291         case 0xc1:
292                 return "(c1)SendCoreBadOp";
293         case 0xc2:
294                 return "(c2)SendCoreBadOp";
295         case 0xc3:
296                 return "(c3)SendCoreBadOp";
297         }
298 }
299
300 char * myCrt_2Dispatch(int i)
301 {
302         switch (i)
303         {
304         default:
305                 return "unknown SMB op-2";
306         case 0:
307                 return "S(00)CreateFile";
308         case 1:
309                 return "S(01)FindFirst";
310         case 2:
311                 return "S(02)FindNext"; /* FindNext */
312         case 3:
313                 return "S(03)QueryFileSystem_ReceiveTran2QFSInfo";
314         case 4:
315                 return "S(04)??";
316         case 5:
317                 return "S(05)QueryFileInfo_ReceiveTran2QPathInfo";
318         case 6:
319                 return "S(06)SetFileInfo_ReceiveTran2SetPathInfo";
320         case 7:
321                 return "S(07)SetInfoHandle_ReceiveTran2QFileInfo";
322         case 8:
323                 return "S(08)??_ReceiveTran2SetFileInfo";
324         case 9:
325                 return "S(09)??_ReceiveTran2FSCTL";
326         case 10:
327                 return "S(0a)_ReceiveTran2IOCTL";
328         case 11:
329                 return "S(0b)_ReceiveTran2FindNotifyFirst";
330         case 12:
331                 return "S(0c)_ReceiveTran2FindNotifyNext";
332         case 13:
333                 return "S(0d)CreateDirectory_ReceiveTran2MKDir";
334         }
335 }
336
337 /* scache must be locked */
338 unsigned int smb_Attributes(cm_scache_t *scp)
339 {
340         unsigned int attrs;
341
342         if (scp->fileType == CM_SCACHETYPE_DIRECTORY
343                 || scp->fileType == CM_SCACHETYPE_MOUNTPOINT)
344                         attrs = SMB_ATTR_DIRECTORY;
345         else
346                 attrs = 0;
347
348         /*
349          * We used to mark a file RO if it was in an RO volume, but that
350          * turns out to be impolitic in NT.  See defect 10007.
351          */
352 #ifdef notdef
353         if ((scp->unixModeBits & 0222) == 0 || (scp->flags & CM_SCACHEFLAG_RO))
354 #endif
355         if ((scp->unixModeBits & 0222) == 0)
356                 attrs |= SMB_ATTR_READONLY;     /* turn on read-only flag */
357
358         return attrs;
359 }
360
361 /* Check if the named file/dir is a dotfile/dotdir */
362 /* String pointed to by lastComp can have leading slashes, but otherwise should have
363    no other patch components */
364 unsigned int smb_IsDotFile(char *lastComp) {
365         char *s;
366         if(lastComp) {
367                 /* skip over slashes */
368         for(s=lastComp;*s && (*s == '\\' || *s == '/'); s++);
369         }
370         else
371                 return 0;
372
373     /* nulls, curdir and parent dir doesn't count */
374         if(!*s) return 0;
375         if(*s == '.') {
376                 if(!*(s + 1)) return 0;
377                 if(*(s+1) == '.' && !*(s + 2)) return 0;
378                 return 1;
379         }
380         return 0;
381 }
382
383 static int ExtractBits(WORD bits, short start, short len)
384 {
385         int end;
386         WORD num;
387
388         end = start + len;
389         
390         num = bits << (16 - end);
391         num = num >> ((16 - end) + start);
392         
393         return (int)num;
394 }
395
396 #ifndef DJGPP
397 void ShowUnixTime(char *FuncName, long unixTime)
398 {
399         FILETIME ft;
400         WORD wDate, wTime;
401
402         smb_LargeSearchTimeFromUnixTime(&ft, unixTime);
403                 
404         if (!FileTimeToDosDateTime(&ft, &wDate, &wTime))
405                 osi_Log1(afsd_logp, "Failed to convert filetime to dos datetime: %d", GetLastError());
406         else {
407                 int day, month, year, sec, min, hour;
408                 char msg[256];
409                 
410                 day = ExtractBits(wDate, 0, 5);
411                 month = ExtractBits(wDate, 5, 4);
412                 year = ExtractBits(wDate, 9, 7) + 1980;
413                 
414                 sec = ExtractBits(wTime, 0, 5);
415                 min = ExtractBits(wTime, 5, 6);
416                 hour = ExtractBits(wTime, 11, 5);
417                 
418                 sprintf(msg, "%s = %02d-%02d-%04d %02d:%02d:%02d", FuncName, month, day, year, hour, min, sec);
419                 osi_Log1(afsd_logp, "%s", osi_LogSaveString(afsd_logp, msg));
420         }
421 }
422 #endif /* DJGPP */
423
424 #ifndef DJGPP
425 /* Determine if we are observing daylight savings time */
426 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
427 {
428         TIME_ZONE_INFORMATION timeZoneInformation;
429         SYSTEMTIME utc, local, localDST;
430
431         /* Get the time zone info. NT uses this to calc if we are in DST. */
432         GetTimeZoneInformation(&timeZoneInformation);
433  
434         /* Return the daylight bias */
435         *pDstBias = timeZoneInformation.DaylightBias;
436
437         /* Return the bias */
438         *pBias = timeZoneInformation.Bias;
439
440         /* Now determine if DST is being observed */
441
442         /* Get the UTC (GMT) time */
443         GetSystemTime(&utc);
444
445         /* Convert UTC time to local time using the time zone info.  If we are
446            observing DST, the calculated local time will include this. 
447         */
448         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &localDST);
449
450         /* Set the daylight bias to 0.  The daylight bias is the amount of change
451            in time that we use for daylight savings time.  By setting this to 0
452            we cause there to be no change in time during daylight savings time. 
453         */
454         timeZoneInformation.DaylightBias = 0;
455
456         /* Convert the utc time to local time again, but this time without any
457            adjustment for daylight savings time. 
458         */
459         SystemTimeToTzSpecificLocalTime(&timeZoneInformation, &utc, &local);
460
461         /* If the two times are different, then it means that the localDST that
462            we calculated includes the daylight bias, and therefore we are
463            observing daylight savings time.
464         */
465         *pDST = localDST.wHour != local.wHour;
466 }
467 #else
468 /* Determine if we are observing daylight savings time */
469 void GetTimeZoneInfo(BOOL *pDST, LONG *pDstBias, LONG *pBias)
470 {
471   struct timeb t;
472
473   ftime(&t);
474   *pDST = t.dstflag;
475   *pDstBias = -60;    /* where can this be different? */
476   *pBias = t.timezone;
477 }
478 #endif /* DJGPP */
479  
480
481 void CompensateForSmbClientLastWriteTimeBugs(long *pLastWriteTime)
482 {
483         BOOL dst;       /* Will be TRUE if observing DST */
484         LONG dstBias;   /* Offset from local time if observing DST */
485         LONG bias;      /* Offset from GMT for local time */
486         
487         /*
488          * This function will adjust the last write time to compensate
489          * for two bugs in the smb client:
490          *
491          *    1) During Daylight Savings Time, the LastWriteTime is ahead
492          *       in time by the DaylightBias (ignoring the sign - the
493          *       DaylightBias is always stored as a negative number).  If
494          *       the DaylightBias is -60, then the LastWriteTime will be
495          *       ahead by 60 minutes.
496          *
497          *    2) If the local time zone is a positive offset from GMT, then
498          *       the LastWriteTime will be the correct local time plus the
499          *       Bias (ignoring the sign - a positive offset from GMT is
500          *       always stored as a negative Bias).  If the Bias is -120,
501          *       then the LastWriteTime will be ahead by 120 minutes.
502          *
503          *    These bugs can occur at the same time.
504          */
505
506         GetTimeZoneInfo(&dst, &dstBias, &bias);
507          
508          /* First adjust for DST */
509         if (dst)
510                 *pLastWriteTime -= (-dstBias * 60);     /* Convert dstBias to seconds */
511                 
512         /* Now adjust for a positive offset from GMT (a negative bias). */
513         if (bias < 0)
514                 *pLastWriteTime -= (-bias * 60);        /* Convert bias to seconds */
515 }
516
517 /*
518  * Calculate the difference (in seconds) between local time and GMT.
519  * This enables us to convert file times to kludge-GMT.
520  */
521 static void
522 smb_CalculateNowTZ()
523 {
524         time_t t;
525         struct tm gmt_tm, local_tm;
526         int days, hours, minutes, seconds;
527
528         t = time(NULL);
529         gmt_tm = *(gmtime(&t));
530         local_tm = *(localtime(&t));
531
532         days = local_tm.tm_yday - gmt_tm.tm_yday;
533         hours = 24 * days + local_tm.tm_hour - gmt_tm.tm_hour;
534         minutes = 60 * hours + local_tm.tm_min - gmt_tm.tm_min;
535         seconds = 60 * minutes + local_tm.tm_sec - gmt_tm.tm_sec;
536
537         smb_NowTZ = seconds;
538 }
539
540 #ifndef DJGPP
541 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
542 {
543         struct tm *ltp;
544         SYSTEMTIME stm;
545         struct tm localJunk;
546         long ersatz_unixTime;
547
548         /*
549          * Must use kludge-GMT instead of real GMT.
550          * kludge-GMT is computed by adding time zone difference to localtime.
551          *
552          * real GMT would be:
553          * ltp = gmtime(&unixTime);
554          */
555         ersatz_unixTime = unixTime - smb_NowTZ;
556         ltp = localtime(&ersatz_unixTime);
557
558         /* if we fail, make up something */
559         if (!ltp) {
560                 ltp = &localJunk;
561                 localJunk.tm_year = 89 - 20;
562                 localJunk.tm_mon = 4;
563                 localJunk.tm_mday = 12;
564                 localJunk.tm_hour = 0;
565                 localJunk.tm_min = 0;
566                 localJunk.tm_sec = 0;
567         }
568
569         stm.wYear = ltp->tm_year + 1900;
570         stm.wMonth = ltp->tm_mon + 1;
571         stm.wDayOfWeek = ltp->tm_wday;
572         stm.wDay = ltp->tm_mday;
573         stm.wHour = ltp->tm_hour;
574         stm.wMinute = ltp->tm_min;
575         stm.wSecond = ltp->tm_sec;
576         stm.wMilliseconds = 0;
577
578         SystemTimeToFileTime(&stm, largeTimep);
579 }
580 #else /* DJGPP */
581 void smb_LargeSearchTimeFromUnixTime(FILETIME *largeTimep, long unixTime)
582 {
583   /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
584   /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 ??? */
585   LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
586   LARGE_INTEGER ut;
587   int leap_years = 89;   /* leap years betw 1/1/1601 and 1/1/1970 */
588
589   /* set ft to number of 100ns intervals betw 1/1/1601 and 1/1/1970 GMT */
590   *ft = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years)
591                                    * 24 * 60);
592   *ft = LargeIntegerMultiplyByLong(*ft, 60);
593   *ft = LargeIntegerMultiplyByLong(*ft, 10000000);
594
595   /* add unix time */
596   ut = ConvertLongToLargeInteger(unixTime);
597   ut = LargeIntegerMultiplyByLong(ut, 10000000);
598   *ft = LargeIntegerAdd(*ft, ut);
599 }
600 #endif /* !DJGPP */
601
602 #ifndef DJGPP
603 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
604 {
605         SYSTEMTIME stm;
606         struct tm lt;
607         long save_timezone;
608
609         FileTimeToSystemTime(largeTimep, &stm);
610
611         lt.tm_year = stm.wYear - 1900;
612         lt.tm_mon = stm.wMonth - 1;
613         lt.tm_wday = stm.wDayOfWeek;
614         lt.tm_mday = stm.wDay;
615         lt.tm_hour = stm.wHour;
616         lt.tm_min = stm.wMinute;
617         lt.tm_sec = stm.wSecond;
618         lt.tm_isdst = -1;
619
620         save_timezone = _timezone;
621         _timezone += smb_NowTZ;
622         *unixTimep = mktime(&lt);
623         _timezone = save_timezone;
624 }
625 #else /* DJGPP */
626 void smb_UnixTimeFromLargeSearchTime(long *unixTimep, FILETIME *largeTimep)
627 {
628   /* unixTime: seconds since 1/1/1970 00:00:00 GMT */
629   /* FILETIME: 100ns intervals since 1/1/1601 00:00:00 GMT? */
630   LARGE_INTEGER *ft = (LARGE_INTEGER *) largeTimep;
631   LARGE_INTEGER a;
632   int leap_years = 89;
633
634   /* set to number of 100ns intervals betw 1/1/1601 and 1/1/1970 */
635   a = ConvertLongToLargeInteger(((EPOCH_YEAR-1601) * 365 + leap_years) * 24 * 60
636 );
637   a = LargeIntegerMultiplyByLong(a, 60);
638   a = LargeIntegerMultiplyByLong(a, 10000000);
639
640   /* subtract it from ft */
641   a = LargeIntegerSubtract(*ft, a);
642
643   /* divide down to seconds */
644   *unixTimep = LargeIntegerDivideByLong(a, 10000000);
645 }
646 #endif /* !DJGPP */
647
648 void smb_SearchTimeFromUnixTime(long *dosTimep, long unixTime)
649 {
650         struct tm *ltp;
651         int dosDate;
652         int dosTime;
653         struct tm localJunk;
654
655         ltp = localtime((time_t*) &unixTime);
656
657         /* if we fail, make up something */
658         if (!ltp) {
659                 ltp = &localJunk;
660                 localJunk.tm_year = 89 - 20;
661                 localJunk.tm_mon = 4;
662                 localJunk.tm_mday = 12;
663                 localJunk.tm_hour = 0;
664                 localJunk.tm_min = 0;
665                 localJunk.tm_sec = 0;
666         }
667
668         dosDate = ((ltp->tm_year-80)<<9) | ((ltp->tm_mon+1) << 5) | (ltp->tm_mday);
669         dosTime = (ltp->tm_hour<<11) | (ltp->tm_min << 5) | (ltp->tm_sec / 2);
670         *dosTimep = (dosDate<<16) | dosTime;
671 }
672
673 void smb_UnixTimeFromSearchTime(long *unixTimep, long searchTime)
674 {
675         unsigned short dosDate;
676         unsigned short dosTime;
677         struct tm localTm;
678         
679         dosDate = searchTime & 0xffff;
680         dosTime = (searchTime >> 16) & 0xffff;
681         
682         localTm.tm_year = 80 + ((dosDate>>9) & 0x3f);
683         localTm.tm_mon = ((dosDate >> 5) & 0xf) - 1;    /* January is 0 in localTm */
684         localTm.tm_mday = (dosDate) & 0x1f;
685         localTm.tm_hour = (dosTime>>11) & 0x1f;
686         localTm.tm_min = (dosTime >> 5) & 0x3f;
687         localTm.tm_sec = (dosTime & 0x1f) * 2;
688         localTm.tm_isdst = -1;                          /* compute whether DST in effect */
689         
690         *unixTimep = mktime(&localTm);
691 }
692
693 void smb_DosUTimeFromUnixTime(long *dosUTimep, long unixTime)
694 {
695         *dosUTimep = unixTime - smb_localZero;
696 }
697
698 void smb_UnixTimeFromDosUTime(long *unixTimep, long dosTime)
699 {
700 #ifndef DJGPP
701         *unixTimep = dosTime + smb_localZero;
702 #else /* DJGPP */
703         /* dosTime seems to be already adjusted for GMT */
704         *unixTimep = dosTime;
705 #endif /* !DJGPP */
706 }
707
708 smb_vc_t *smb_FindVC(unsigned short lsn, int flags, int lana)
709 {
710         smb_vc_t *vcp;
711
712         lock_ObtainWrite(&smb_rctLock);
713         for(vcp = smb_allVCsp; vcp; vcp=vcp->nextp) {
714                 if (lsn == vcp->lsn && lana == vcp->lana) {
715                         vcp->refCount++;
716                         break;
717                 }
718         }
719         if (!vcp && (flags & SMB_FLAG_CREATE)) {
720                 vcp = malloc(sizeof(*vcp));
721                 memset(vcp, 0, sizeof(*vcp));
722                 vcp->refCount = 1;
723                 vcp->tidCounter = 1;
724                 vcp->fidCounter = 1;
725                 vcp->uidCounter = 1;  /* UID 0 is reserved for blank user */
726                 vcp->nextp = smb_allVCsp;
727                 smb_allVCsp = vcp;
728                 lock_InitializeMutex(&vcp->mx, "vc_t mutex");
729                 vcp->lsn = lsn;
730                 vcp->lana = lana;
731         }
732         lock_ReleaseWrite(&smb_rctLock);
733         return vcp;
734 }
735
736 int smb_IsStarMask(char *maskp)
737 {
738         int i;
739         char tc;
740         
741         for(i=0; i<11; i++) {
742                 tc = *maskp++;
743                 if (tc == '?' || tc == '*' || tc == '>') return 1;        
744         }
745         return 0;
746 }
747
748 void smb_ReleaseVC(smb_vc_t *vcp)
749 {
750         lock_ObtainWrite(&smb_rctLock);
751         osi_assert(vcp->refCount-- > 0);
752         lock_ReleaseWrite(&smb_rctLock);
753 }
754
755 void smb_HoldVC(smb_vc_t *vcp)
756 {
757         lock_ObtainWrite(&smb_rctLock);
758         vcp->refCount++;
759         lock_ReleaseWrite(&smb_rctLock);
760 }
761
762 smb_tid_t *smb_FindTID(smb_vc_t *vcp, unsigned short tid, int flags)
763 {
764         smb_tid_t *tidp;
765
766         lock_ObtainWrite(&smb_rctLock);
767         for(tidp = vcp->tidsp; tidp; tidp = tidp->nextp) {
768                 if (tid == tidp->tid) {
769                         tidp->refCount++;
770                         break;
771                 }
772         }
773         if (!tidp && (flags & SMB_FLAG_CREATE)) {
774                 tidp = malloc(sizeof(*tidp));
775                 memset(tidp, 0, sizeof(*tidp));
776                 tidp->nextp = vcp->tidsp;
777                 tidp->refCount = 1;
778                 tidp->vcp = vcp;
779                 vcp->tidsp = tidp;
780                 lock_InitializeMutex(&tidp->mx, "tid_t mutex");
781                 tidp->tid = tid;
782         }
783         lock_ReleaseWrite(&smb_rctLock);
784         return tidp;
785 }
786
787 void smb_ReleaseTID(smb_tid_t *tidp)
788 {
789         smb_tid_t *tp;
790         smb_tid_t **ltpp;
791         cm_user_t *userp;
792
793         userp = NULL;
794         lock_ObtainWrite(&smb_rctLock);
795         osi_assert(tidp->refCount-- > 0);
796         if (tidp->refCount == 0 && (tidp->flags & SMB_TIDFLAG_DELETE)) {
797                 ltpp = &tidp->vcp->tidsp;
798                 for(tp = *ltpp; tp; ltpp = &tp->nextp, tp = *ltpp) {
799                         if (tp == tidp) break;
800                 }
801                 osi_assert(tp != NULL);
802                 *ltpp = tp->nextp;
803                 lock_FinalizeMutex(&tidp->mx);
804                 userp = tidp->userp;    /* remember to drop ref later */
805         }
806         lock_ReleaseWrite(&smb_rctLock);
807         if (userp) {
808                 cm_ReleaseUser(userp);
809         }
810 }
811
812 smb_user_t *smb_FindUID(smb_vc_t *vcp, unsigned short uid, int flags)
813 {
814         smb_user_t *uidp = NULL;
815
816         lock_ObtainWrite(&smb_rctLock);
817         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
818                 if (uid == uidp->userID) {
819                         uidp->refCount++;
820                         osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL," VCP[%x] found-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp) ? uidp->unp->name : "");
821                 break;
822                 }
823         }
824         if (!uidp && (flags & SMB_FLAG_CREATE)) {
825                 uidp = malloc(sizeof(*uidp));
826                 memset(uidp, 0, sizeof(*uidp));
827                 uidp->nextp = vcp->usersp;
828                 uidp->refCount = 1;
829                 uidp->vcp = vcp;
830                 vcp->usersp = uidp;
831                 lock_InitializeMutex(&uidp->mx, "uid_t mutex");
832                 uidp->userID = uid;
833                                 osi_LogEvent("AFS smb_FindUID (Find by UID)",NULL,"VCP[%x] new-uid[%d] name[%s]",(int)vcp,uidp->userID,(uidp->unp ? uidp->unp->name : ""));
834         }
835         lock_ReleaseWrite(&smb_rctLock);
836         return uidp;
837 }
838
839 smb_username_t *smb_FindUserByName(char *usern, char *machine, int flags)
840 {
841         smb_username_t *unp= NULL;
842
843         lock_ObtainWrite(&smb_rctLock);
844         for(unp = usernamesp; unp; unp = unp->nextp) {
845                 if (stricmp(unp->name, usern) == 0 &&
846                     stricmp(unp->machine, machine) == 0) {
847                         unp->refCount++;
848                         break;
849                 }
850         }
851         if (!unp && (flags & SMB_FLAG_CREATE)) {
852           unp = malloc(sizeof(*unp));
853           memset(unp, 0, sizeof(*unp));
854           unp->refCount = 1;
855           unp->nextp = usernamesp;
856           unp->name = strdup(usern);
857           unp->machine = strdup(machine);
858           usernamesp = unp;
859           lock_InitializeMutex(&unp->mx, "username_t mutex");
860         }
861         lock_ReleaseWrite(&smb_rctLock);
862         return unp;
863 }
864
865 smb_user_t *smb_FindUserByNameThisSession(smb_vc_t *vcp, char *usern)
866 {
867         smb_user_t *uidp= NULL;
868
869         lock_ObtainWrite(&smb_rctLock);
870         for(uidp = vcp->usersp; uidp; uidp = uidp->nextp) {
871           if (!uidp->unp) 
872             continue;
873           if (stricmp(uidp->unp->name, usern) == 0) {
874             uidp->refCount++;
875                         osi_LogEvent("AFS smb_FindUserByNameThisSession",NULL,"VCP[%x] uid[%d] match-name[%s]",(int)vcp,uidp->userID,usern);
876             break;
877           } else
878             continue;
879         }
880         lock_ReleaseWrite(&smb_rctLock);
881         return uidp;
882 }
883 void smb_ReleaseUID(smb_user_t *uidp)
884 {
885         smb_user_t *up;
886         smb_user_t **lupp;
887         cm_user_t *userp;
888
889         userp = NULL;
890         lock_ObtainWrite(&smb_rctLock);
891         osi_assert(uidp->refCount-- > 0);
892         if (uidp->refCount == 0 && (uidp->flags & SMB_USERFLAG_DELETE)) {
893                 lupp = &uidp->vcp->usersp;
894                 for(up = *lupp; up; lupp = &up->nextp, up = *lupp) {
895                         if (up == uidp) break;
896                 }
897                 osi_assert(up != NULL);
898                 *lupp = up->nextp;
899                 lock_FinalizeMutex(&uidp->mx);
900                 if (uidp->unp)
901                   userp = uidp->unp->userp;     /* remember to drop ref later */
902         }
903         lock_ReleaseWrite(&smb_rctLock);
904         if (userp) {
905                 cm_ReleaseUserVCRef(userp);
906                 cm_ReleaseUser(userp);
907         }
908 }
909
910 /* retrieve a held reference to a user structure corresponding to an incoming
911  * request.
912  * corresponding release function is cm_ReleaseUser.
913  */
914 cm_user_t *smb_GetUser(smb_vc_t *vcp, smb_packet_t *inp)
915 {
916         smb_user_t *uidp;
917         cm_user_t *up;
918         smb_t *smbp;
919         
920         smbp = (smb_t *) inp;
921         uidp = smb_FindUID(vcp, smbp->uid, 0);
922         if ((!uidp) ||  (!uidp->unp))
923                  return NULL;
924         
925         lock_ObtainMutex(&uidp->mx);
926         up = uidp->unp->userp;
927         cm_HoldUser(up);
928         lock_ReleaseMutex(&uidp->mx);
929
930         smb_ReleaseUID(uidp);
931         
932         return up;
933 }
934
935 /*
936  * Return a pointer to a pathname extracted from a TID structure.  The
937  * TID structure is not held; assume it won't go away.
938  */
939 char *smb_GetTIDPath(smb_vc_t *vcp, unsigned short tid)
940 {
941         smb_tid_t *tidp;
942         char *tpath;
943
944         tidp = smb_FindTID(vcp, tid, 0);
945     if (!tidp) 
946         return NULL;
947         tpath = tidp->pathname;
948         smb_ReleaseTID(tidp);
949         return tpath;
950 }
951
952 /* check to see if we have a chained fid, that is, a fid that comes from an
953  * OpenAndX message that ran earlier in this packet.  In this case, the fid
954  * field in a read, for example, request, isn't set, since the value is
955  * supposed to be inherited from the openAndX call.
956  */
957 int smb_ChainFID(int fid, smb_packet_t *inp)
958 {
959         if (inp->fid == 0 || inp->inCount == 0) return fid;
960         else return inp->fid;
961 }
962
963 /* are we a priv'd user?  What does this mean on NT? */
964 int smb_SUser(cm_user_t *userp)
965 {
966         return 1;
967 }
968
969 /* find a file ID.  If pass in 0, we'll allocate on on a create operation. */
970 smb_fid_t *smb_FindFID(smb_vc_t *vcp, unsigned short fid, int flags)
971 {
972         smb_fid_t *fidp;
973         int newFid;
974         
975         /* figure out if we need to allocate a new file ID */
976         if (fid == 0) {
977                 newFid = 1;
978                 fid = vcp->fidCounter;
979         }
980         else newFid = 0;
981
982         lock_ObtainWrite(&smb_rctLock);
983 retry:
984         for(fidp = vcp->fidsp; fidp; fidp = (smb_fid_t *) osi_QNext(&fidp->q)) {
985                 if (fid == fidp->fid) {
986                         if (newFid) {
987                                 fid++;
988                 if (fid == 0) fid = 1;
989                 goto retry;
990             }
991                         fidp->refCount++;
992             break;
993                 }
994     }
995     if (!fidp && (flags & SMB_FLAG_CREATE)) {
996         char eventName[MAX_PATH];
997         sprintf(eventName,"fid_t event fid=%d", fid);
998                 fidp = malloc(sizeof(*fidp));
999         memset(fidp, 0, sizeof(*fidp));
1000                 osi_QAdd((osi_queue_t **)&vcp->fidsp, &fidp->q);
1001         fidp->refCount = 1;
1002         fidp->vcp = vcp;
1003         lock_InitializeMutex(&fidp->mx, "fid_t mutex");
1004         fidp->fid = fid;
1005                 fidp->curr_chunk = fidp->prev_chunk = -2;
1006                 fidp->raw_write_event = thrd_CreateEvent(NULL, FALSE, TRUE, eventName);
1007         if ( GetLastError() == ERROR_ALREADY_EXISTS )
1008             afsi_log("Event Object Already Exists: %s", eventName);
1009         if (newFid) {
1010                         vcp->fidCounter = fid+1;
1011             if (vcp->fidCounter == 0) vcp->fidCounter = 1;
1012         }
1013     }
1014     lock_ReleaseWrite(&smb_rctLock);
1015     return fidp;
1016 }
1017
1018 void smb_ReleaseFID(smb_fid_t *fidp)
1019 {
1020         cm_scache_t *scp;
1021     smb_vc_t *vcp;
1022     smb_ioctl_t *ioctlp;
1023
1024     if (!fidp)
1025         return NULL;
1026
1027         scp = NULL;
1028         lock_ObtainWrite(&smb_rctLock);
1029         osi_assert(fidp->refCount-- > 0);
1030     if (fidp->refCount == 0 && (fidp->flags & SMB_FID_DELETE)) {
1031                 vcp = fidp->vcp;
1032                 if (!(fidp->flags & SMB_FID_IOCTL))
1033                         scp = fidp->scp;
1034                 osi_QRemove((osi_queue_t **) &vcp->fidsp, &fidp->q);
1035                 thrd_CloseHandle(fidp->raw_write_event);
1036
1037                 /* and see if there is ioctl stuff to free */
1038         ioctlp = fidp->ioctlp;
1039         if (ioctlp) {
1040                         if (ioctlp->prefix) cm_FreeSpace(ioctlp->prefix);
1041                         if (ioctlp->inAllocp) free(ioctlp->inAllocp);
1042                         if (ioctlp->outAllocp) free(ioctlp->outAllocp);
1043                         free(ioctlp);
1044         }
1045
1046         free(fidp);
1047     }
1048         lock_ReleaseWrite(&smb_rctLock);
1049
1050         /* now release the scache structure */
1051         if (scp) cm_ReleaseSCache(scp);
1052 }
1053
1054 /*
1055  * Case-insensitive search for one string in another;
1056  * used to find variable names in submount pathnames.
1057  */
1058 static char *smb_stristr(char *str1, char *str2)
1059 {
1060         char *cursor;
1061
1062         for (cursor = str1; *cursor; cursor++)
1063                 if (stricmp(cursor, str2) == 0)
1064                         return cursor;
1065
1066         return NULL;
1067 }
1068
1069 /*
1070  * Substitute a variable value for its name in a submount pathname.  Variable
1071  * name has been identified by smb_stristr() and is in substr.  Variable name
1072  * length (plus one) is in substr_size.  Variable value is in newstr.
1073  */
1074 static void smb_subst(char *str1, char *substr, unsigned int substr_size,
1075         char *newstr)
1076 {
1077         char temp[1024];
1078
1079         strcpy(temp, substr + substr_size - 1);
1080         strcpy(substr, newstr);
1081         strcat(str1, temp);
1082 }
1083
1084 char VNUserName[] = "%USERNAME%";
1085 char VNLCUserName[] = "%LCUSERNAME%";
1086 char VNComputerName[] = "%COMPUTERNAME%";
1087 char VNLCComputerName[] = "%LCCOMPUTERNAME%";
1088
1089 /* List available shares */
1090 int smb_ListShares()
1091 {
1092         char sbmtpath[256];
1093         char pathName[256];
1094         char shareBuf[4096];
1095         int num_shares=0;
1096         char *this_share;
1097         int len;
1098         char *p;
1099         int print_afs = 0;
1100         int code;
1101
1102         /*strcpy(shareNameList[num_shares], "all");
1103           strcpy(pathNameList[num_shares++], "/afs");*/
1104         fprintf(stderr, "The following shares are available:\n");
1105         fprintf(stderr, "Share Name (AFS Path)\n");
1106         fprintf(stderr, "---------------------\n");
1107         fprintf(stderr, "\\\\%s\\%-16s (%s)\n", smb_localNamep, "ALL", cm_mountRoot);
1108
1109 #ifndef DJGPP
1110         code = GetWindowsDirectory(sbmtpath, sizeof(sbmtpath));
1111         if (code == 0 || code > sizeof(sbmtpath)) return -1;
1112 #else
1113         strcpy(sbmtpath, cm_confDir);
1114 #endif /* !DJGPP */
1115         strcat(sbmtpath, "/afsdsbmt.ini");
1116         len = GetPrivateProfileString("AFS Submounts", NULL, NULL,
1117                                       shareBuf, sizeof(shareBuf),
1118                                       sbmtpath);
1119         if (len == 0) {
1120           return num_shares;
1121         }
1122
1123         this_share = shareBuf;
1124         do
1125         {
1126           print_afs = 0;
1127           /*strcpy(shareNameList[num_shares], this_share);*/
1128           len = GetPrivateProfileString("AFS Submounts", this_share,
1129                                         NULL,
1130                                         pathName, 256,
1131                                         sbmtpath);
1132           if (!len) return num_shares;
1133           p = pathName;
1134           if (strncmp(p, cm_mountRoot, 4) != 0)
1135             print_afs = 1;
1136           while (*p) {
1137             if (*p == '\\') *p = '/';    /* change to / */
1138             p++;
1139           }
1140
1141           fprintf(stderr, "\\\\%s\\%-16s (%s%s)\n",
1142                   smb_localNamep, this_share, (print_afs ? cm_mountRoot : "\0"),
1143                   pathName);
1144           num_shares++;
1145           while (*this_share != 0) this_share++;  /* find next NUL */
1146           this_share++;   /* skip past the NUL */
1147         } while (*this_share != 0);  /* stop at final NUL */
1148
1149         return num_shares;
1150 }
1151
1152 /* find a shareName in the table of submounts */
1153 int smb_FindShare(smb_vc_t *vcp, smb_packet_t *inp, char *shareName,
1154         char **pathNamep)
1155 {
1156         DWORD len;
1157         char pathName[1024];
1158         char *var;
1159         smb_user_t *uidp;
1160         char temp[1024];
1161         DWORD sizeTemp;
1162     char sbmtpath[256];
1163     char *p, *q;
1164         HKEY parmKey;
1165         DWORD code;
1166     DWORD allSubmount = 1;
1167
1168         if (strcmp(shareName, "IPC$") == 0) {
1169                 *pathNamep = NULL;
1170                 return 0;
1171         }
1172
1173     /* if allSubmounts == 0, only return the //mountRoot/all share 
1174      * if in fact it has been been created in the subMounts table.  
1175      * This is to allow sites that want to restrict access to the 
1176      * world to do so.
1177      */
1178         code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSConfigKeyName,
1179                                 0, KEY_QUERY_VALUE, &parmKey);
1180         if (code == ERROR_SUCCESS) {
1181         len = sizeof(allSubmount);
1182         code = RegQueryValueEx(parmKey, "AllSubmount", NULL, NULL,
1183                                 (BYTE *) &allSubmount, &len);
1184         if (code != ERROR_SUCCESS) {
1185             allSubmount = 1;
1186         }
1187         RegCloseKey (parmKey);
1188         }
1189
1190         if (allSubmount && _stricmp(shareName, "all") == 0) {
1191                 *pathNamep = NULL;
1192                 return 1;
1193         }
1194
1195     /* In case, the all share is disabled we need to still be able
1196      * to handle ioctl requests 
1197      */
1198         if (_stricmp(shareName, "ioctl$") == 0) {
1199                 *pathNamep = "/.__ioctl__";
1200                 return 1;
1201         }
1202
1203 #ifndef DJGPP
1204         strcpy(sbmtpath, "afsdsbmt.ini");
1205 #else /* DJGPP */
1206         strcpy(sbmtpath, cm_confDir);
1207         strcat(sbmtpath, "/afsdsbmt.ini");
1208 #endif /* !DJGPP */
1209         len = GetPrivateProfileString("AFS Submounts", shareName, "",
1210                                       pathName, sizeof(pathName), sbmtpath);
1211         if (len == 0 || len == sizeof(pathName) - 1) {
1212                 *pathNamep = NULL;
1213                 return 0;
1214         }
1215         
1216         /* We can accept either unix or PC style AFS pathnames.  Convert
1217            Unix-style to PC style here for internal use. */
1218         p = pathName;
1219         if (strncmp(p, cm_mountRoot, 4) == 0)
1220           p += strlen(cm_mountRoot);  /* skip mount path */
1221         q = p;
1222         while (*q) {
1223           if (*q == '/') *q = '\\';    /* change to \ */
1224           q++;
1225         }
1226
1227         while (1)
1228         {
1229                 if (var = smb_stristr(p, VNUserName)) {
1230                         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1231                         if (uidp && uidp->unp)
1232                           smb_subst(p, var, sizeof(VNUserName),
1233                                        uidp->unp->name);
1234                         else
1235                           smb_subst(p, var, sizeof(VNUserName),
1236                                        " ");
1237                         if (uidp)
1238                 smb_ReleaseUID(uidp);
1239                 }
1240                 else if (var = smb_stristr(p, VNLCUserName)) {
1241                         uidp = smb_FindUID(vcp, ((smb_t *)inp)->uid, 0);
1242                         if (uidp && uidp->unp)
1243                           strcpy(temp, uidp->unp->name);
1244                         else strcpy(temp, " ");
1245                         _strlwr(temp);
1246                         smb_subst(p, var, sizeof(VNLCUserName), temp);
1247                         if (uidp)
1248                 smb_ReleaseUID(uidp);
1249                 }
1250                 else if (var = smb_stristr(p, VNComputerName)) {
1251                         sizeTemp = sizeof(temp);
1252                         GetComputerName((LPTSTR)temp, &sizeTemp);
1253                         smb_subst(p, var, sizeof(VNComputerName),
1254                                   temp);
1255                 }
1256                 else if (var = smb_stristr(p, VNLCComputerName)) {
1257                         sizeTemp = sizeof(temp);
1258                         GetComputerName((LPTSTR)temp, &sizeTemp);
1259                         _strlwr(temp);
1260                         smb_subst(p, var, sizeof(VNLCComputerName),
1261                                   temp);
1262                 }
1263                 else break;
1264         }
1265
1266         *pathNamep = strdup(p);
1267         return 1;
1268 }
1269
1270 /* find a dir search structure by cookie value, and return it held.
1271  * Must be called with smb_globalLock held.
1272  */
1273 smb_dirSearch_t *smb_FindDirSearchNL(long cookie)
1274 {
1275         smb_dirSearch_t *dsp;
1276         
1277         for(dsp = smb_firstDirSearchp; dsp; dsp = (smb_dirSearch_t *) osi_QNext(&dsp->q)) {
1278                 if (dsp->cookie == cookie) {
1279                         if (dsp != smb_firstDirSearchp) {
1280                                 /* move to head of LRU queue, too, if we're not already there */
1281                                 if (smb_lastDirSearchp == (smb_dirSearch_t *) &dsp->q)
1282                                         smb_lastDirSearchp = (smb_dirSearch_t *)
1283                                                 osi_QPrev(&dsp->q);
1284                                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1285                                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1286                                 if (!smb_lastDirSearchp)
1287                                         smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1288                         }
1289                         dsp->refCount++;
1290                         break;
1291                 }
1292         }
1293         return dsp;
1294 }
1295
1296 void smb_DeleteDirSearch(smb_dirSearch_t *dsp)
1297 {
1298         lock_ObtainWrite(&smb_globalLock);
1299         dsp->flags |= SMB_DIRSEARCH_DELETE;
1300         lock_ReleaseWrite(&smb_globalLock);
1301         lock_ObtainMutex(&dsp->mx);
1302         if(dsp->scp != NULL) {
1303               lock_ObtainMutex(&dsp->scp->mx);
1304               if (dsp->flags & SMB_DIRSEARCH_BULKST) {
1305                     dsp->flags &= ~SMB_DIRSEARCH_BULKST;
1306                     dsp->scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
1307                     dsp->scp->bulkStatProgress = hones;
1308               }
1309               lock_ReleaseMutex(&dsp->scp->mx);
1310         }
1311         lock_ReleaseMutex(&dsp->mx);
1312 }
1313
1314 void smb_ReleaseDirSearch(smb_dirSearch_t *dsp)
1315 {
1316         cm_scache_t *scp;
1317         
1318         scp = NULL;
1319
1320         lock_ObtainWrite(&smb_globalLock);
1321         osi_assert(dsp->refCount-- > 0);
1322         if (dsp->refCount == 0 && (dsp->flags & SMB_DIRSEARCH_DELETE)) {
1323                 if (&dsp->q == (osi_queue_t *) smb_lastDirSearchp)
1324                         smb_lastDirSearchp = (smb_dirSearch_t *) osi_QPrev(&smb_lastDirSearchp->q);
1325                 osi_QRemove((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1326                 lock_FinalizeMutex(&dsp->mx);
1327                 scp = dsp->scp;
1328                 free(dsp);
1329         }
1330         lock_ReleaseWrite(&smb_globalLock);
1331         
1332         /* do this now to avoid spurious locking hierarchy creation */
1333         if (scp) cm_ReleaseSCache(scp);
1334 }
1335
1336 /* find a dir search structure by cookie value, and return it held */
1337 smb_dirSearch_t *smb_FindDirSearch(long cookie)
1338 {
1339         smb_dirSearch_t *dsp;
1340
1341         lock_ObtainWrite(&smb_globalLock);
1342         dsp = smb_FindDirSearchNL(cookie);
1343         lock_ReleaseWrite(&smb_globalLock);
1344         return dsp;
1345 }
1346
1347 /* GC some dir search entries, in the address space expected by the specific protocol.
1348  * Must be called with smb_globalLock held; release the lock temporarily.
1349  */
1350 #define SMB_DIRSEARCH_GCMAX     10      /* how many at once */
1351 void smb_GCDirSearches(int isV3)
1352 {
1353         smb_dirSearch_t *prevp;
1354         smb_dirSearch_t *tp;
1355         smb_dirSearch_t *victimsp[SMB_DIRSEARCH_GCMAX];
1356         int victimCount;
1357         int i;
1358         
1359         victimCount = 0;        /* how many have we got so far */
1360         for(tp = smb_lastDirSearchp; tp; tp=prevp) {
1361                 prevp = (smb_dirSearch_t *) osi_QPrev(&tp->q);  /* we'll move tp from queue, so
1362                                                                  * do this early.
1363                                                                  */
1364                 /* if no one is using this guy, and we're either in the new protocol,
1365                  * or we're in the old one and this is a small enough ID to be useful
1366                  * to the old protocol, GC this guy.
1367                  */
1368                 if (tp->refCount == 0 && (isV3 || tp->cookie <= 255)) {
1369                         /* hold and delete */
1370                         tp->flags |= SMB_DIRSEARCH_DELETE;
1371                         victimsp[victimCount++] = tp;
1372                         tp->refCount++;
1373                 }
1374
1375                 /* don't do more than this */
1376                 if (victimCount >= SMB_DIRSEARCH_GCMAX) break;
1377         }
1378         
1379         /* now release them */
1380         lock_ReleaseWrite(&smb_globalLock);
1381         for(i = 0; i < victimCount; i++) {
1382                 smb_ReleaseDirSearch(victimsp[i]);
1383         }
1384         lock_ObtainWrite(&smb_globalLock);
1385 }
1386
1387 /* function for allocating a dir search entry.  We need these to remember enough context
1388  * since we don't get passed the path from call to call during a directory search.
1389  *
1390  * Returns a held dir search structure, and bumps the reference count on the vnode,
1391  * since it saves a pointer to the vnode.
1392  */
1393 smb_dirSearch_t *smb_NewDirSearch(int isV3)
1394 {
1395         smb_dirSearch_t *dsp;
1396         int counter;
1397         int maxAllowed;
1398
1399         lock_ObtainWrite(&smb_globalLock);
1400         counter = 0;
1401
1402         /* what's the biggest ID allowed in this version of the protocol */
1403         if (isV3) maxAllowed = 65535;
1404         else maxAllowed = 255;
1405
1406         while(1) {
1407                 /* twice so we have enough tries to find guys we GC after one pass;
1408                  * 10 extra is just in case I mis-counted.
1409                  */
1410                 if (++counter > 2*maxAllowed+10) osi_panic("afsd: dir search cookie leak",
1411                         __FILE__, __LINE__);
1412                 if (smb_dirSearchCounter > maxAllowed) {
1413                         smb_dirSearchCounter = 1;
1414                         smb_GCDirSearches(isV3);        /* GC some (drops global lock) */
1415                 }
1416                 dsp = smb_FindDirSearchNL(smb_dirSearchCounter);
1417                 if (dsp) {
1418                         /* don't need to watch for refcount zero and deleted, since
1419                          * we haven't dropped the global lock.
1420                          */
1421                         dsp->refCount--;
1422                         ++smb_dirSearchCounter;
1423                         continue;
1424                 }
1425                 
1426                 dsp = malloc(sizeof(*dsp));
1427                 memset(dsp, 0, sizeof(*dsp));
1428                 osi_QAdd((osi_queue_t **) &smb_firstDirSearchp, &dsp->q);
1429                 if (!smb_lastDirSearchp) smb_lastDirSearchp = (smb_dirSearch_t *) &dsp->q;
1430                 dsp->cookie = smb_dirSearchCounter;
1431                 ++smb_dirSearchCounter;
1432                 dsp->refCount = 1;
1433                 lock_InitializeMutex(&dsp->mx, "cm_dirSearch_t");
1434                 dsp->lastTime = osi_Time();
1435                 break;
1436         }
1437         lock_ReleaseWrite(&smb_globalLock);
1438         return dsp;
1439 }
1440
1441 static smb_packet_t *GetPacket(void)
1442 {
1443         smb_packet_t *tbp;
1444 #ifdef DJGPP
1445         unsigned int npar, seg, tb_sel;
1446 #endif
1447
1448         lock_ObtainWrite(&smb_globalLock);
1449         tbp = smb_packetFreeListp;
1450     if (tbp) 
1451         smb_packetFreeListp = tbp->nextp;
1452         lock_ReleaseWrite(&smb_globalLock);
1453     if (!tbp) {
1454 #ifndef DJGPP
1455         tbp = calloc(65540,1);
1456 #else /* DJGPP */
1457         tbp = malloc(sizeof(smb_packet_t));
1458 #endif /* !DJGPP */
1459         tbp->magic = SMB_PACKETMAGIC;
1460                 tbp->ncbp = NULL;
1461                 tbp->vcp = NULL;
1462                 tbp->resumeCode = 0;
1463                 tbp->inCount = 0;
1464                 tbp->fid = 0;
1465                 tbp->wctp = NULL;
1466                 tbp->inCom = 0;
1467                 tbp->oddByte = 0;
1468                 tbp->ncb_length = 0;
1469                 tbp->flags = 0;
1470         tbp->spacep = NULL;
1471         
1472 #ifdef DJGPP
1473         npar = SMB_PACKETSIZE >> 4;  /* number of paragraphs */
1474         {
1475             signed int retval =
1476                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1477             if (retval == -1) {
1478                 afsi_log("Cannot allocate %d paragraphs of DOS memory",
1479                           npar);
1480                 osi_panic("",__FILE__,__LINE__);
1481             }
1482             else {
1483                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X",
1484                           npar, retval);
1485                 seg = retval;
1486             }
1487         }
1488         tbp->dos_pkt = (seg * 16) + 0;  /* DOS physical address */
1489         tbp->dos_pkt_sel = tb_sel;
1490 #endif /* DJGPP */
1491         }
1492     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1493
1494     return tbp;
1495 }
1496
1497 smb_packet_t *smb_CopyPacket(smb_packet_t *pkt)
1498 {
1499         smb_packet_t *tbp;
1500         tbp = GetPacket();
1501         memcpy(tbp, pkt, sizeof(smb_packet_t));
1502         tbp->wctp = tbp->data + ((unsigned int)pkt->wctp - (unsigned int)pkt->data);
1503         return tbp;
1504 }
1505
1506 static NCB *GetNCB(void)
1507 {
1508         smb_ncb_t *tbp;
1509     NCB *ncbp;
1510 #ifdef DJGPP
1511     unsigned int npar, seg, tb_sel;
1512 #endif /* DJGPP */
1513
1514         lock_ObtainWrite(&smb_globalLock);
1515         tbp = smb_ncbFreeListp;
1516     if (tbp) 
1517         smb_ncbFreeListp = tbp->nextp;
1518         lock_ReleaseWrite(&smb_globalLock);
1519     if (!tbp) {
1520 #ifndef DJGPP
1521         tbp = calloc(sizeof(*tbp),1);
1522 #else /* DJGPP */
1523         tbp = malloc(sizeof(*tbp));
1524         npar = (sizeof(NCB)+15) >> 4;  /* number of paragraphs */
1525         {
1526             signed int retval =
1527                 __dpmi_allocate_dos_memory(npar, &tb_sel); /* DOS segment */
1528             if (retval == -1) {
1529                 afsi_log("Cannot allocate %d paragraphs of DOS mem in GetNCB",
1530                           npar);
1531                 osi_panic("",__FILE__,__LINE__);
1532             } else {
1533                 afsi_log("Allocated %d paragraphs of DOS mem at 0x%X in GetNCB",
1534                           npar, retval);
1535                 seg = retval;
1536             }
1537         }
1538         tbp->dos_ncb = (seg * 16) + 0;  /* DOS physical address */
1539         tbp->dos_ncb_sel = tb_sel;
1540 #endif /* !DJGPP */
1541         tbp->magic = SMB_NCBMAGIC;
1542         }
1543         
1544     osi_assert(tbp->magic == SMB_NCBMAGIC);
1545
1546         memset(&tbp->ncb, 0, sizeof(NCB));
1547     ncbp = &tbp->ncb;
1548 #ifdef DJGPP
1549     dos_memset(tbp->dos_ncb, 0, sizeof(NCB));
1550 #endif /* DJGPP */
1551     return ncbp;
1552 }
1553
1554 void smb_FreePacket(smb_packet_t *tbp)
1555 {
1556     osi_assert(tbp->magic == SMB_PACKETMAGIC);
1557         
1558     lock_ObtainWrite(&smb_globalLock);
1559         tbp->nextp = smb_packetFreeListp;
1560         smb_packetFreeListp = tbp;
1561         tbp->magic = SMB_PACKETMAGIC;
1562         tbp->ncbp = NULL;
1563         tbp->vcp = NULL;
1564         tbp->resumeCode = 0;
1565         tbp->inCount = 0;
1566         tbp->fid = 0;
1567         tbp->wctp = NULL;
1568         tbp->inCom = 0;
1569         tbp->oddByte = 0;
1570         tbp->ncb_length = 0;
1571         tbp->flags = 0;
1572     lock_ReleaseWrite(&smb_globalLock);
1573 }
1574
1575 static void FreeNCB(NCB *bufferp)
1576 {
1577         smb_ncb_t *tbp;
1578         
1579     tbp = (smb_ncb_t *) bufferp;
1580     osi_assert(tbp->magic == SMB_NCBMAGIC);
1581         
1582     lock_ObtainWrite(&smb_globalLock);
1583         tbp->nextp = smb_ncbFreeListp;
1584         smb_ncbFreeListp = tbp;
1585     lock_ReleaseWrite(&smb_globalLock);
1586 }
1587
1588 /* get a ptr to the data part of a packet, and its count */
1589 unsigned char *smb_GetSMBData(smb_packet_t *smbp, int *nbytesp)
1590 {
1591     int parmBytes;
1592     int dataBytes;
1593     unsigned char *afterParmsp;
1594
1595     parmBytes = *smbp->wctp << 1;
1596         afterParmsp = smbp->wctp + parmBytes + 1;
1597         
1598     dataBytes = afterParmsp[0] + (afterParmsp[1]<<8);
1599     if (nbytesp) *nbytesp = dataBytes;
1600         
1601         /* don't forget to skip the data byte count, since it follows
1602      * the parameters; that's where the "2" comes from below.
1603      */
1604     return (unsigned char *) (afterParmsp + 2);
1605 }
1606
1607 /* must set all the returned parameters before playing around with the
1608  * data region, since the data region is located past the end of the
1609  * variable number of parameters.
1610  */
1611 void smb_SetSMBDataLength(smb_packet_t *smbp, unsigned int dsize)
1612 {
1613         unsigned char *afterParmsp;
1614
1615         afterParmsp = smbp->wctp + ((*smbp->wctp)<<1) + 1;
1616         
1617         *afterParmsp++ = dsize & 0xff;
1618         *afterParmsp = (dsize>>8) & 0xff;
1619 }
1620
1621 /* return the parm'th parameter in the smbp packet */
1622 unsigned int smb_GetSMBParm(smb_packet_t *smbp, int parm)
1623 {
1624         int parmCount;
1625         unsigned char *parmDatap;
1626
1627         parmCount = *smbp->wctp;
1628
1629         if (parm >= parmCount) {
1630 #ifndef DJGPP
1631         HANDLE h;
1632                 char *ptbuf[1];
1633                 char s[100];
1634                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1635                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1636                         parm, parmCount, smbp->ncb_length);
1637                 ptbuf[0] = s;
1638                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1639                             1, smbp->ncb_length, ptbuf, smbp);
1640                 DeregisterEventSource(h);
1641 #else /* DJGPP */
1642                 char s[100];
1643
1644                 sprintf(s, "Bad SMB param %d out of %d, ncb len %d",
1645                         parm, parmCount, smbp->ncb_length);
1646                 osi_Log0(afsd_logp, s);
1647 #endif /* !DJGPP */
1648                 osi_panic(s, __FILE__, __LINE__);
1649         }
1650         parmDatap = smbp->wctp + (2*parm) + 1;
1651         
1652         return parmDatap[0] + (parmDatap[1] << 8);
1653 }
1654
1655 /* return the parm'th parameter in the smbp packet */
1656 unsigned int smb_GetSMBOffsetParm(smb_packet_t *smbp, int parm, int offset)
1657 {
1658         int parmCount;
1659         unsigned char *parmDatap;
1660
1661         parmCount = *smbp->wctp;
1662
1663         if (parm * 2 + offset >= parmCount * 2) {
1664 #ifndef DJGPP
1665                 HANDLE h;
1666                 char *ptbuf[1];
1667                 char s[100];
1668                 h = RegisterEventSource(NULL, AFS_DAEMON_EVENT_NAME);
1669                 sprintf(s, "Bad SMB param %d offset %d out of %d, ncb len %d",
1670                         parm, offset, parmCount, smbp->ncb_length);
1671                 ptbuf[0] = s;
1672                 ReportEvent(h, EVENTLOG_ERROR_TYPE, 0, 1006, NULL,
1673                             1, smbp->ncb_length, ptbuf, smbp);
1674                 DeregisterEventSource(h);
1675 #else /* DJGPP */
1676                 char s[100];
1677                 
1678                 sprintf(s, "Bad SMB param %d offset %d out of %d, "
1679                         "ncb len %d",
1680                         parm, offset, parmCount, smbp->ncb_length);
1681                 osi_Log0(afsd_logp, s);
1682 #endif /* !DJGPP */
1683
1684                 osi_panic(s, __FILE__, __LINE__);
1685         }
1686         parmDatap = smbp->wctp + (2*parm) + 1 + offset;
1687         
1688         return parmDatap[0] + (parmDatap[1] << 8);
1689 }
1690
1691 void smb_SetSMBParm(smb_packet_t *smbp, int slot, unsigned int parmValue)
1692 {
1693         char *parmDatap;
1694
1695         /* make sure we have enough slots */
1696         if (*smbp->wctp <= slot) *smbp->wctp = slot+1;
1697         
1698         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1699         *parmDatap++ = parmValue & 0xff;
1700         *parmDatap = (parmValue>>8) & 0xff;
1701 }
1702
1703 void smb_SetSMBParmLong(smb_packet_t *smbp, int slot, unsigned int parmValue)
1704 {
1705         char *parmDatap;
1706
1707         /* make sure we have enough slots */
1708         if (*smbp->wctp <= slot) *smbp->wctp = slot+2;
1709
1710         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1711         *parmDatap++ = parmValue & 0xff;
1712         *parmDatap++ = (parmValue>>8) & 0xff;
1713         *parmDatap++ = (parmValue>>16) & 0xff;
1714         *parmDatap++ = (parmValue>>24) & 0xff;
1715 }
1716
1717 void smb_SetSMBParmDouble(smb_packet_t *smbp, int slot, char *parmValuep)
1718 {
1719         char *parmDatap;
1720         int i;
1721
1722         /* make sure we have enough slots */
1723         if (*smbp->wctp <= slot) *smbp->wctp = slot+4;
1724
1725         parmDatap = smbp->wctp + 2*slot + 1 + smbp->oddByte;
1726         for (i=0; i<8; i++)
1727                 *parmDatap++ = *parmValuep++;
1728 }
1729
1730 void smb_SetSMBParmByte(smb_packet_t *smbp, int slot, unsigned int parmValue)
1731 {
1732         char *parmDatap;
1733
1734         /* make sure we have enough slots */
1735         if (*smbp->wctp <= slot) {
1736                 if (smbp->oddByte) {
1737                         smbp->oddByte = 0;
1738                         *smbp->wctp = slot+1;
1739                 } else
1740                         smbp->oddByte = 1;
1741         }
1742
1743         parmDatap = smbp->wctp + 2*slot + 1 + (1 - smbp->oddByte);
1744         *parmDatap++ = parmValue & 0xff;
1745 }
1746
1747 void smb_StripLastComponent(char *outPathp, char **lastComponentp, char *inPathp)
1748 {
1749         char *lastSlashp;
1750         
1751         lastSlashp = strrchr(inPathp, '\\');
1752         if (lastComponentp)
1753                 *lastComponentp = lastSlashp;
1754         if (lastSlashp) {
1755                 while (1) {
1756                         if (inPathp == lastSlashp) break;
1757                         *outPathp++ = *inPathp++;
1758                 }
1759                 *outPathp++ = 0;
1760         }
1761         else {
1762                 *outPathp++ = 0;
1763         }
1764 }
1765
1766 unsigned char *smb_ParseASCIIBlock(unsigned char *inp, char **chainpp)
1767 {
1768         if (*inp++ != 0x4) return NULL;
1769         if (chainpp) {
1770                 *chainpp = inp + strlen(inp) + 1;       /* skip over null-terminated string */
1771         }
1772         return inp;
1773 }
1774
1775 unsigned char *smb_ParseVblBlock(unsigned char *inp, char **chainpp, int *lengthp)
1776 {
1777         int tlen;
1778
1779         if (*inp++ != 0x5) return NULL;
1780         tlen = inp[0] + (inp[1]<<8);
1781         inp += 2;               /* skip length field */
1782         
1783         if (chainpp) {
1784                 *chainpp = inp + tlen;
1785         }
1786         
1787         if (lengthp) *lengthp = tlen;
1788         
1789         return inp;
1790 }
1791
1792 /* format a packet as a response */
1793 void smb_FormatResponsePacket(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *op)
1794 {
1795         smb_t *outp;
1796         smb_t *inSmbp;
1797
1798         outp = (smb_t *) op;
1799         
1800         /* zero the basic structure through the smb_wct field, and zero the data
1801          * size field, assuming that wct stays zero; otherwise, you have to 
1802          * explicitly set the data size field, too.
1803          */
1804         inSmbp = (smb_t *) inp;
1805         memset(outp, 0, sizeof(smb_t)+2);
1806         outp->id[0] = 0xff;
1807         outp->id[1] = 'S';
1808         outp->id[2] = 'M';
1809         outp->id[3] = 'B';
1810         if (inp) {
1811                 outp->com = inSmbp->com;
1812                 outp->tid = inSmbp->tid;
1813                 outp->pid = inSmbp->pid;
1814                 outp->uid = inSmbp->uid;
1815                 outp->mid = inSmbp->mid;
1816                 outp->res[0] = inSmbp->res[0];
1817                 outp->res[1] = inSmbp->res[1];
1818                 op->inCom = inSmbp->com;
1819         }
1820         outp->reb = 0x80;       /* SERVER_RESP */
1821         outp->flg2 = 0x1;       /* KNOWS_LONG_NAMES */
1822
1823         /* copy fields in generic packet area */
1824         op->wctp = &outp->wct;
1825 }
1826
1827 /* send a (probably response) packet; vcp tells us to whom to send it.
1828  * we compute the length by looking at wct and bcc fields.
1829  */
1830 void smb_SendPacket(smb_vc_t *vcp, smb_packet_t *inp)
1831 {
1832         NCB *ncbp;
1833         int extra;
1834         long code;
1835         unsigned char *tp;
1836         int localNCB = 0;
1837 #ifdef DJGPP
1838         dos_ptr dos_ncb;
1839 #endif /* DJGPP */
1840         
1841         ncbp = inp->ncbp;
1842         if (ncbp == NULL) {
1843                 ncbp = GetNCB();
1844                 localNCB = 1;
1845         }
1846 #ifdef DJGPP
1847         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
1848 #endif /* DJGPP */
1849  
1850         memset((char *)ncbp, 0, sizeof(NCB));
1851
1852         extra = 2 * (*inp->wctp);       /* space used by parms, in bytes */
1853         tp = inp->wctp + 1+ extra;      /* points to count of data bytes */
1854         extra += tp[0] + (tp[1]<<8);
1855         extra += ((unsigned int)inp->wctp - (unsigned int)inp->data);   /* distance to last wct field */
1856         extra += 3;                     /* wct and length fields */
1857         
1858         ncbp->ncb_length = extra;       /* bytes to send */
1859         ncbp->ncb_lsn = (unsigned char) vcp->lsn;       /* vc to use */
1860         ncbp->ncb_lana_num = vcp->lana;
1861         ncbp->ncb_command = NCBSEND;    /* op means send data */
1862 #ifndef DJGPP
1863         ncbp->ncb_buffer = (char *) inp;/* packet */
1864         code = Netbios(ncbp);
1865 #else /* DJGPP */
1866         ncbp->ncb_buffer = inp->dos_pkt;/* packet */
1867         ((smb_ncb_t*)ncbp)->orig_pkt = inp;
1868
1869         /* copy header information from virtual to DOS address space */
1870         dosmemput((char*)inp, SMB_PACKETSIZE, inp->dos_pkt);
1871         code = Netbios(ncbp, dos_ncb);
1872 #endif /* !DJGPP */
1873         
1874         if (code != 0)
1875                 osi_Log1(afsd_logp, "SendPacket failure code %d", code);
1876
1877         if (localNCB)
1878                 FreeNCB(ncbp);
1879 }
1880
1881 void smb_MapNTError(long code, unsigned long *NTStatusp)
1882 {
1883         unsigned long NTStatus;
1884
1885         /* map CM_ERROR_* errors to NT 32-bit status codes */
1886         if (code == CM_ERROR_NOSUCHCELL) {
1887                 NTStatus = 0xC000000FL; /* No such file */
1888         }
1889         else if (code == CM_ERROR_NOSUCHVOLUME) {
1890                 NTStatus = 0xC000000FL; /* No such file */
1891         }
1892         else if (code == CM_ERROR_TIMEDOUT) {
1893             NTStatus = 0xC00000CFL;     /* Sharing Paused */
1894         }
1895         else if (code == CM_ERROR_RETRY) {
1896                 NTStatus = 0xC000022DL; /* Retry */
1897         }
1898         else if (code == CM_ERROR_NOACCESS) {
1899                 NTStatus = 0xC0000022L; /* Access denied */
1900         }
1901         else if (code == CM_ERROR_READONLY) {
1902                 NTStatus = 0xC00000A2L; /* Write protected */
1903         }
1904         else if (code == CM_ERROR_NOSUCHFILE) {
1905                 NTStatus = 0xC000000FL; /* No such file */
1906         }
1907         else if (code == CM_ERROR_NOSUCHPATH) {
1908                 NTStatus = 0xC000003AL; /* Object path not found */
1909         }
1910         else if (code == CM_ERROR_TOOBIG) {
1911                 NTStatus = 0xC000007BL; /* Invalid image format */
1912         }
1913         else if (code == CM_ERROR_INVAL) {
1914                 NTStatus = 0xC000000DL; /* Invalid parameter */
1915         }
1916         else if (code == CM_ERROR_BADFD) {
1917                 NTStatus = 0xC0000008L; /* Invalid handle */
1918         }
1919         else if (code == CM_ERROR_BADFDOP) {
1920                 NTStatus = 0xC0000022L; /* Access denied */
1921         }
1922         else if (code == CM_ERROR_EXISTS) {
1923                 NTStatus = 0xC0000035L; /* Object name collision */
1924         }
1925         else if (code == CM_ERROR_NOTEMPTY) {
1926                 NTStatus = 0xC0000101L; /* Directory not empty */
1927         }
1928         else if (code == CM_ERROR_CROSSDEVLINK) {
1929                 NTStatus = 0xC00000D4L; /* Not same device */
1930         }
1931         else if (code == CM_ERROR_NOTDIR) {
1932                 NTStatus = 0xC0000103L; /* Not a directory */
1933         }
1934         else if (code == CM_ERROR_ISDIR) {
1935                 NTStatus = 0xC00000BAL; /* File is a directory */
1936         }
1937         else if (code == CM_ERROR_BADOP) {
1938                 NTStatus = 0xC09820FFL; /* SMB no support */
1939         }
1940         else if (code == CM_ERROR_BADSHARENAME) {
1941                 NTStatus = 0xC00000CCL; /* Bad network name */
1942         }
1943         else if (code == CM_ERROR_NOIPC) {
1944 #ifdef COMMENT
1945                 NTStatus = 0xC0000022L; /* Access Denied */
1946 #else
1947         NTStatus = 0xC000013DL; /* Remote Resources */
1948 #endif
1949         }
1950         else if (code == CM_ERROR_CLOCKSKEW) {
1951                 NTStatus = 0xC0000133L; /* Time difference at DC */
1952         }
1953         else if (code == CM_ERROR_BADTID) {
1954                 NTStatus = 0xC0982005L; /* SMB bad TID */
1955         }
1956         else if (code == CM_ERROR_USESTD) {
1957                 NTStatus = 0xC09820FBL; /* SMB use standard */
1958         }
1959         else if (code == CM_ERROR_QUOTA) {
1960                 NTStatus = 0xC0000044L; /* Quota exceeded */
1961         }
1962         else if (code == CM_ERROR_SPACE) {
1963                 NTStatus = 0xC000007FL; /* Disk full */
1964         }
1965         else if (code == CM_ERROR_ATSYS) {
1966                 NTStatus = 0xC0000033L; /* Object name invalid */
1967         }
1968         else if (code == CM_ERROR_BADNTFILENAME) {
1969                 NTStatus = 0xC0000033L; /* Object name invalid */
1970         }
1971         else if (code == CM_ERROR_WOULDBLOCK) {
1972                 NTStatus = 0xC0000055L; /* Lock not granted */
1973         }
1974         else if (code == CM_ERROR_PARTIALWRITE) {
1975                 NTStatus = 0xC000007FL; /* Disk full */
1976         }
1977         else if (code == CM_ERROR_BUFFERTOOSMALL) {
1978                 NTStatus = 0xC0000023L; /* Buffer too small */
1979         }
1980         else {
1981                 NTStatus = 0xC0982001L; /* SMB non-specific error */
1982         }
1983
1984         *NTStatusp = NTStatus;
1985         osi_Log2(afsd_logp, "SMB SEND code %x as NT %x", code, NTStatus);
1986 }
1987
1988 void smb_MapCoreError(long code, smb_vc_t *vcp, unsigned short *scodep,
1989         unsigned char *classp)
1990 {
1991         unsigned char class;
1992         unsigned short error;
1993
1994         /* map CM_ERROR_* errors to SMB errors */
1995         if (code == CM_ERROR_NOSUCHCELL) {
1996                 class = 1;
1997                 error = 3;      /* bad path */
1998         }
1999         else if (code == CM_ERROR_NOSUCHVOLUME) {
2000                 class = 1;
2001                 error = 3;      /* bad path */
2002         }
2003         else if (code == CM_ERROR_TIMEDOUT) {
2004                 class = 2;
2005                 error = 81;     /* server is paused */
2006         }
2007         else if (code == CM_ERROR_RETRY) {
2008                 class = 2;      /* shouldn't happen */
2009                 error = 1;
2010         }
2011         else if (code == CM_ERROR_NOACCESS) {
2012                 class = 2;
2013                 error = 4;      /* bad access */
2014         }
2015         else if (code == CM_ERROR_READONLY) {
2016                 class = 3;
2017                 error = 19;     /* read only */
2018         }
2019         else if (code == CM_ERROR_NOSUCHFILE) {
2020                 class = 1;
2021                 error = 2;      /* ENOENT! */
2022         }
2023         else if (code == CM_ERROR_NOSUCHPATH) {
2024                 class = 1;
2025                 error = 3;      /* Bad path */
2026         }
2027         else if (code == CM_ERROR_TOOBIG) {
2028                 class = 1;
2029                 error = 11;     /* bad format */
2030         }
2031         else if (code == CM_ERROR_INVAL) {
2032                 class = 2;      /* server non-specific error code */
2033                 error = 1;
2034         }
2035         else if (code == CM_ERROR_BADFD) {
2036                 class = 1;
2037                 error = 6;      /* invalid file handle */
2038         }
2039         else if (code == CM_ERROR_BADFDOP) {
2040                 class = 1;      /* invalid op on FD */
2041                 error = 5;
2042         }
2043         else if (code == CM_ERROR_EXISTS) {
2044                 class = 1;
2045                 error = 80;     /* file already exists */
2046         }
2047         else if (code == CM_ERROR_NOTEMPTY) {
2048                 class = 1;
2049                 error = 5;      /* delete directory not empty */
2050         }
2051         else if (code == CM_ERROR_CROSSDEVLINK) {
2052                 class = 1;
2053                 error = 17;     /* EXDEV */
2054         }
2055         else if (code == CM_ERROR_NOTDIR) {
2056                 class = 1;      /* bad path */
2057                 error = 3;
2058         }
2059         else if (code == CM_ERROR_ISDIR) {
2060                 class = 1;      /* access denied; DOS doesn't have a good match */
2061                 error = 5;
2062         }
2063         else if (code == CM_ERROR_BADOP) {
2064                 class = 2;
2065                 error = 65535;
2066         }
2067         else if (code == CM_ERROR_BADSHARENAME) {
2068                 class = 2;
2069                 error = 6;
2070         }
2071         else if (code == CM_ERROR_NOIPC) {
2072                 class = 2;
2073                 error = 4; /* bad access */
2074         }
2075         else if (code == CM_ERROR_CLOCKSKEW) {
2076                 class = 1;      /* invalid function */
2077                 error = 1;
2078         }
2079         else if (code == CM_ERROR_BADTID) {
2080                 class = 2;
2081                 error = 5;
2082         }
2083         else if (code == CM_ERROR_USESTD) {
2084                 class = 2;
2085                 error = 251;
2086         }
2087         else if (code == CM_ERROR_REMOTECONN) {
2088                 class = 2;
2089                 error = 82;
2090         }
2091         else if (code == CM_ERROR_QUOTA) {
2092                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2093                         class = 3;
2094                         error = 39;     /* disk full */
2095                 }
2096                 else {
2097                         class = 1;
2098                         error = 5;      /* access denied */
2099                 }
2100         }
2101         else if (code == CM_ERROR_SPACE) {
2102                 if (vcp->flags & SMB_VCFLAG_USEV3) {
2103                         class = 3;
2104                         error = 39;     /* disk full */
2105                 }
2106                 else {
2107                         class = 1;
2108                         error = 5;      /* access denied */
2109                 }
2110         }
2111         else if (code == CM_ERROR_PARTIALWRITE) {
2112                 class = 3;
2113                 error = 39;     /* disk full */
2114         }
2115         else if (code == CM_ERROR_ATSYS) {
2116                 class = 1;
2117                 error = 2;      /* ENOENT */
2118         }
2119         else if (code == CM_ERROR_WOULDBLOCK) {
2120                 class = 1;
2121                 error = 33;     /* lock conflict */
2122         }
2123         else if (code == CM_ERROR_NOFILES) {
2124                 class = 1;
2125                 error = 18;     /* no files in search */
2126         }
2127         else if (code == CM_ERROR_RENAME_IDENTICAL) {
2128                 class = 1;
2129                 error = 183;     /* Samba uses this */
2130         }
2131         else {
2132                 class = 2;
2133                 error = 1;
2134         }
2135
2136         *scodep = error;
2137         *classp = class;
2138         osi_Log3(afsd_logp, "SMB SEND code %x as SMB %d: %d", code, class, error);
2139 }
2140
2141 long smb_SendCoreBadOp(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2142 {
2143         return CM_ERROR_BADOP;
2144 }
2145
2146 long smb_ReceiveCoreEcho(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2147 {
2148         unsigned short EchoCount, i;
2149         char *data, *outdata;
2150         int dataSize;
2151
2152         EchoCount = (unsigned short) smb_GetSMBParm(inp, 0);
2153
2154         for (i=1; i<=EchoCount; i++) {
2155             data = smb_GetSMBData(inp, &dataSize);
2156             smb_SetSMBParm(outp, 0, i);
2157             smb_SetSMBDataLength(outp, dataSize);
2158             outdata = smb_GetSMBData(outp, NULL);
2159             memcpy(outdata, data, dataSize);
2160             smb_SendPacket(vcp, outp);
2161         }
2162
2163         return 0;
2164 }
2165
2166 long smb_ReceiveCoreReadRaw(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2167 {
2168         osi_hyper_t offset;
2169         long count, minCount, finalCount;
2170         unsigned short fd;
2171         smb_fid_t *fidp;
2172         long code;
2173         cm_user_t *userp = NULL;
2174         NCB *ncbp;
2175         int rc;
2176 #ifndef DJGPP
2177         char *rawBuf = NULL;
2178 #else
2179         dos_ptr rawBuf = NULL;
2180         dos_ptr dos_ncb;
2181 #endif /* DJGPP */
2182
2183         rawBuf = NULL;
2184         finalCount = 0;
2185
2186         fd = smb_GetSMBParm(inp, 0);
2187         count = smb_GetSMBParm(inp, 3);
2188         minCount = smb_GetSMBParm(inp, 4);
2189         offset.HighPart = 0;    /* too bad */
2190         offset.LowPart = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
2191
2192         osi_Log3(afsd_logp, "smb_ReceieveCoreReadRaw fd %d, off 0x%x, size 0x%x",
2193                  fd, offset.LowPart, count);
2194
2195         fidp = smb_FindFID(vcp, fd, 0);
2196         if (!fidp)
2197                 goto send1;
2198
2199         lock_ObtainMutex(&smb_RawBufLock);
2200         if (smb_RawBufs) {
2201                 /* Get a raw buf, from head of list */
2202                 rawBuf = smb_RawBufs;
2203 #ifndef DJGPP
2204                 smb_RawBufs = *(char **)smb_RawBufs;
2205 #else /* DJGPP */
2206                 smb_RawBufs = _farpeekl(_dos_ds, smb_RawBufs);
2207 #endif /* !DJGPP */
2208         }
2209         lock_ReleaseMutex(&smb_RawBufLock);
2210         if (!rawBuf)
2211                 goto send1a;
2212
2213         if (fidp->flags & SMB_FID_IOCTL)
2214         {
2215 #ifndef DJGPP
2216           rc = smb_IoctlReadRaw(fidp, vcp, inp, outp);
2217 #else
2218           rc = smb_IoctlReadRaw(fidp, vcp, inp, outp, rawBuf);
2219 #endif
2220           if (rawBuf) {
2221             /* Give back raw buffer */
2222             lock_ObtainMutex(&smb_RawBufLock);
2223 #ifndef DJGPP
2224             *((char **) rawBuf) = smb_RawBufs;
2225 #else /* DJGPP */
2226             _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2227 #endif /* !DJGPP */
2228             
2229             smb_RawBufs = rawBuf;
2230             lock_ReleaseMutex(&smb_RawBufLock);
2231           }
2232           return rc;
2233         }
2234         
2235         userp = smb_GetUser(vcp, inp);
2236
2237 #ifndef DJGPP
2238         code = smb_ReadData(fidp, &offset, count, rawBuf, userp, &finalCount);
2239 #else /* DJGPP */
2240         /* have to give ReadData flag so it will treat buffer as DOS mem. */
2241         code = smb_ReadData(fidp, &offset, count, (unsigned char *)rawBuf,
2242                             userp, &finalCount, TRUE /* rawFlag */);
2243 #endif /* !DJGPP */
2244
2245         if (code != 0)
2246                 goto send;
2247
2248 send:
2249         cm_ReleaseUser(userp);
2250 send1a:
2251         smb_ReleaseFID(fidp);
2252
2253 send1:
2254         ncbp = outp->ncbp;
2255 #ifdef DJGPP
2256         dos_ncb = ((smb_ncb_t *)ncbp)->dos_ncb;
2257 #endif /* DJGPP */
2258         memset((char *)ncbp, 0, sizeof(NCB));
2259
2260         ncbp->ncb_length = (unsigned short) finalCount;
2261         ncbp->ncb_lsn = (unsigned char) vcp->lsn;
2262         ncbp->ncb_lana_num = vcp->lana;
2263         ncbp->ncb_command = NCBSEND;
2264         ncbp->ncb_buffer = rawBuf;
2265
2266 #ifndef DJGPP
2267         code = Netbios(ncbp);
2268 #else /* DJGPP */
2269         code = Netbios(ncbp, dos_ncb);
2270 #endif /* !DJGPP */
2271         if (code != 0)
2272                 osi_Log1(afsd_logp, "ReadRaw send failure code %d", code);
2273
2274         if (rawBuf) {
2275                 /* Give back raw buffer */
2276                 lock_ObtainMutex(&smb_RawBufLock);
2277 #ifndef DJGPP
2278                 *((char **) rawBuf) = smb_RawBufs;
2279 #else /* DJGPP */
2280                 _farpokel(_dos_ds, rawBuf, smb_RawBufs);
2281 #endif /* !DJGPP */
2282
2283                 smb_RawBufs = rawBuf;
2284                 lock_ReleaseMutex(&smb_RawBufLock);
2285         }
2286
2287         return 0;
2288 }
2289
2290 long smb_ReceiveCoreLockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2291 {
2292         return 0;
2293 }
2294
2295 long smb_ReceiveCoreUnlockRecord(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2296 {
2297         return 0;
2298 }
2299
2300 long smb_ReceiveNegotiate(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2301 {
2302         char *namep;
2303         int coreProtoIndex;
2304         int v3ProtoIndex;
2305         int NTProtoIndex;
2306         int protoIndex;                 /* index we're using */
2307         int namex;
2308         int dbytes;
2309         int entryLength;
2310         int tcounter;
2311         char protocol_array[10][1024]; /* protocol signature of the client */
2312
2313         
2314         osi_Log1(afsd_logp, "SMB receive negotiate; %d + 1 ongoing ops",
2315                  ongoingOps - 1);
2316         if (!isGateway) {
2317                 if (active_vcp) {
2318                         DWORD now = GetCurrentTime();
2319                         if (now - last_msg_time >= 30000
2320                               && now - last_msg_time <= 90000) {
2321                                 osi_Log1(afsd_logp,
2322                                          "Setting dead_vcp %x", active_vcp);
2323                                 dead_vcp = active_vcp;
2324                                 dead_vcp->flags |= SMB_VCFLAG_ALREADYDEAD;
2325                         }
2326                 }
2327         }
2328
2329         inp->flags |= SMB_PACKETFLAG_PROFILE_UPDATE_OK;
2330
2331         namep = smb_GetSMBData(inp, &dbytes);
2332         namex = 0;
2333         tcounter = 0;
2334         coreProtoIndex = -1;            /* not found */
2335         v3ProtoIndex = -1;
2336         NTProtoIndex = -1;
2337         while(namex < dbytes) {
2338                 osi_Log1(afsd_logp, "Protocol %s",
2339                          osi_LogSaveString(afsd_logp, namep+1));
2340                 strcpy(protocol_array[tcounter], namep+1);
2341
2342                 /* namep points at the first protocol, or really, a 0x02
2343                  * byte preceding the null-terminated ASCII name.
2344                  */
2345                 if (strcmp("PC NETWORK PROGRAM 1.0", namep+1) == 0) {
2346                         coreProtoIndex = tcounter;
2347                 }
2348                 else if (smb_useV3 && strcmp("LM1.2X002", namep+1) == 0) {
2349                         v3ProtoIndex = tcounter;
2350                 }
2351                 else if (smb_useV3 && strcmp("NT LM 0.12", namep+1) == 0) {
2352                         NTProtoIndex = tcounter;
2353                 }
2354
2355                 /* compute size of protocol entry */
2356                 entryLength = strlen(namep+1);
2357         entryLength += 2;       /* 0x02 bytes and null termination */
2358                 
2359         /* advance over this protocol entry */
2360                 namex += entryLength;
2361         namep += entryLength;
2362         tcounter++;             /* which proto entry we're looking at */
2363         }
2364 #ifndef NOMOREFILESFIX
2365         /* 
2366          * NOTE: We can determine what OS (NT4.0, W2K, W9X, etc)
2367          * the client is running by reading the protocol signature.
2368          * ie. the order in which it sends us the protocol list.
2369          *
2370          * Special handling for Windows 2000 clients (defect 11765 )
2371      * <asanka:11Jun03> Proto signature is the same for Win XP. </>
2372          */
2373         if (tcounter == 6) {
2374                int i = 0;
2375                smb_t *ip = (smb_t *) inp;
2376                smb_t *op = (smb_t *) outp;
2377
2378                if ((strcmp("PC NETWORK PROGRAM 1.0", protocol_array[0]) == 0) &&
2379                    (strcmp("LANMAN1.0", protocol_array[1]) == 0) &&
2380                    (strcmp("Windows for Workgroups 3.1a", protocol_array[2]) == 0) &&
2381                    (strcmp("LM1.2X002", protocol_array[3]) == 0) &&
2382                    (strcmp("LANMAN2.1", protocol_array[4]) == 0) &&
2383                    (strcmp("NT LM 0.12", protocol_array[5]) == 0)) {
2384                       isWindows2000 = TRUE;
2385                       osi_Log0(afsd_logp, "Looks like a Windows 2000 client");
2386                       /* 
2387                        * HACK: for now - just negotiate a lower protocol till we 
2388                        * figure out which flag/flag2 or some other field 
2389                        * (capabilities maybe?) to set in order for this to work
2390                        * correctly with Windows 2000 clients (defect 11765)
2391                        */
2392                       NTProtoIndex = -1;
2393                       /* Things to try (after looking at tcpdump output could be
2394                        * setting flags and flags2 to 0x98 and 0xc853 like this
2395                        * op->reb = 0x98; op->flg2 = 0xc853;
2396                        * osi_Log2(afsd_logp, "Flags:0x%x Flags2:0x%x", ip->reb, ip->flg2);
2397                        */
2398                }
2399         }
2400 #endif /* NOMOREFILESFIX */
2401
2402         if (NTProtoIndex != -1) {
2403                 protoIndex = NTProtoIndex;
2404                 vcp->flags |= (SMB_VCFLAG_USENT | SMB_VCFLAG_USEV3);
2405         }
2406         else if (v3ProtoIndex != -1) {
2407                 protoIndex = v3ProtoIndex;
2408                 vcp->flags |= SMB_VCFLAG_USEV3;
2409         }
2410         else if (coreProtoIndex != -1) {
2411                 protoIndex = coreProtoIndex;
2412                 vcp->flags |= SMB_VCFLAG_USECORE;
2413         }
2414         else protoIndex = -1;
2415
2416         if (protoIndex == -1)
2417                 return CM_ERROR_INVAL;
2418         else if (NTProtoIndex != -1) {
2419                 smb_SetSMBParm(outp, 0, protoIndex);
2420         smb_SetSMBParmByte(outp, 1, 0); /* share level security, no passwd encrypt */
2421         smb_SetSMBParm(outp, 1, smb_maxMpxRequests);    /* max multiplexed requests */
2422         smb_SetSMBParm(outp, 2, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2423         smb_SetSMBParmLong(outp, 3, SMB_PACKETSIZE); /* xmit buffer size */
2424                 smb_SetSMBParmLong(outp, 5, 65536);     /* raw buffer size */
2425         smb_SetSMBParm(outp, 7, 1);     /* next 2: session key */
2426         smb_SetSMBParm(outp, 8, 1);
2427                 /* 
2428                  * Tried changing the capabilities to support for W2K - defect 117695
2429                  * Maybe something else needs to be changed here?
2430                  */
2431                 /*
2432                   if (isWindows2000) 
2433                   smb_SetSMBParmLong(outp, 9, 0x43fd);
2434                   else 
2435                   smb_SetSMBParmLong(outp, 9, 0x251);
2436                   */
2437                 smb_SetSMBParmLong(outp, 9, 0x251);     /* Capabilities: *
2438                                                  * 32-bit error codes *
2439                                                  * and NT Find *
2440                                                  * and NT SMB's *
2441                                                  * and raw mode */
2442                 smb_SetSMBParmLong(outp, 11, 0);/* XXX server time: do we need? */
2443                 smb_SetSMBParmLong(outp, 13, 0);/* XXX server date: do we need? */
2444                 smb_SetSMBParm(outp, 15, 0);    /* XXX server tzone: do we need? */
2445                 smb_SetSMBParmByte(outp, 16, 0);/* Encryption key length */
2446                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2447         }
2448         else if (v3ProtoIndex != -1) {
2449                 smb_SetSMBParm(outp, 0, protoIndex);
2450                 smb_SetSMBParm(outp, 1, 0);     /* share level security, no passwd encrypt */
2451                 smb_SetSMBParm(outp, 2, SMB_PACKETSIZE);
2452                 smb_SetSMBParm(outp, 3, smb_maxMpxRequests);    /* max multiplexed requests */
2453                 smb_SetSMBParm(outp, 4, smb_maxVCPerServer);    /* max VCs per consumer/server connection */
2454                 smb_SetSMBParm(outp, 5, 0);     /* no support of block mode for read or write */
2455                 smb_SetSMBParm(outp, 6, 1);     /* next 2: session key */
2456                 smb_SetSMBParm(outp, 7, 1);
2457                 smb_SetSMBParm(outp, 8, 0);     /* XXX server time: do we need? */
2458                 smb_SetSMBParm(outp, 9, 0);     /* XXX server date: do we need? */
2459                 smb_SetSMBParm(outp, 10, 0);    /* XXX server tzone: do we need? */
2460                 smb_SetSMBParm(outp, 11, 0);    /* resvd */
2461                 smb_SetSMBParm(outp, 12, 0);    /* resvd */
2462                 smb_SetSMBDataLength(outp, 0);  /* perhaps should specify 8 bytes anyway */
2463         }
2464         else if (coreProtoIndex != -1) {
2465                 smb_SetSMBParm(outp, 0, protoIndex);
2466                 smb_SetSMBDataLength(outp, 0);
2467         }
2468         return 0;
2469 }
2470
2471 void smb_Daemon(void *parmp)
2472 {
2473         int count = 0;
2474
2475         while(1) {
2476                 count++;
2477                 thrd_Sleep(10000);
2478                 if ((count % 360) == 0)         /* every hour */
2479                         smb_CalculateNowTZ();
2480                 /* XXX GC dir search entries */
2481         }
2482 }
2483
2484 void smb_WaitingLocksDaemon()
2485 {
2486         smb_waitingLock_t *wL, *nwL;
2487         int first;
2488         smb_vc_t *vcp;
2489         smb_packet_t *inp, *outp;
2490         NCB *ncbp;
2491         long code;
2492
2493         while(1) {
2494                 lock_ObtainWrite(&smb_globalLock);
2495                 nwL = smb_allWaitingLocks;
2496                 if (nwL == NULL) {
2497                         osi_SleepW((long)&smb_allWaitingLocks, &smb_globalLock);
2498                         thrd_Sleep(1000);
2499                         continue;
2500                 }
2501                 else first = 1;
2502                 do {
2503                         if (first)
2504                                 first = 0;
2505                         else
2506                                 lock_ObtainWrite(&smb_globalLock);
2507                         wL = nwL;
2508                         nwL = (smb_waitingLock_t *) osi_QNext(&wL->q);
2509                         lock_ReleaseWrite(&smb_globalLock);
2510                         code = cm_RetryLock((cm_file_lock_t *) wL->lockp,
2511                                 wL->vcp->flags & SMB_VCFLAG_ALREADYDEAD);
2512                         if (code == CM_ERROR_WOULDBLOCK) {
2513                                 /* no progress */
2514                                 if (wL->timeRemaining != 0xffffffff
2515                                     && (wL->timeRemaining -= 1000) < 0)
2516                                         goto endWait;
2517                                 continue;
2518                         }
2519 endWait:
2520                         vcp = wL->vcp;
2521                         inp = wL->inp;
2522                         outp = wL->outp;
2523                         ncbp = GetNCB();
2524                         ncbp->ncb_length = inp->ncb_length;
2525                         inp->spacep = cm_GetSpace();
2526
2527                         /* Remove waitingLock from list */
2528                         lock_ObtainWrite(&smb_globalLock);
2529                         osi_QRemove((osi_queue_t **)&smb_allWaitingLocks,
2530                                     &wL->q);
2531                         lock_ReleaseWrite(&smb_globalLock);
2532
2533                         /* Resume packet processing */
2534                         if (code == 0)
2535                                 smb_SetSMBDataLength(outp, 0);
2536                         outp->flags |= SMB_PACKETFLAG_SUSPENDED;
2537                         outp->resumeCode = code;
2538                         outp->ncbp = ncbp;
2539                         smb_DispatchPacket(vcp, inp, outp, ncbp, NULL);
2540
2541                         /* Clean up */
2542                         cm_FreeSpace(inp->spacep);
2543                         smb_FreePacket(inp);
2544                         smb_FreePacket(outp);
2545                         FreeNCB(ncbp);
2546                         free(wL);
2547                 } while (nwL);
2548                 thrd_Sleep(1000);
2549         }
2550 }
2551
2552 long smb_ReceiveCoreGetDiskAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2553 {
2554         osi_Log0(afsd_logp, "SMB receive get disk attributes");
2555
2556         smb_SetSMBParm(outp, 0, 32000);
2557         smb_SetSMBParm(outp, 1, 64);
2558         smb_SetSMBParm(outp, 2, 1024);
2559         smb_SetSMBParm(outp, 3, 30000);
2560         smb_SetSMBParm(outp, 4, 0);
2561         smb_SetSMBDataLength(outp, 0);
2562         return 0;
2563 }
2564
2565 long smb_ReceiveCoreTreeConnect(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *rsp)
2566 {
2567         smb_tid_t *tidp;
2568         unsigned short newTid;
2569         char shareName[256];
2570         char *sharePath;
2571         int shareFound;
2572         char *tp;
2573         char *pathp;
2574         char *passwordp;
2575         cm_user_t *userp;
2576         
2577         osi_Log0(afsd_logp, "SMB receive tree connect");
2578
2579         /* parse input parameters */
2580         tp = smb_GetSMBData(inp, NULL);
2581         pathp = smb_ParseASCIIBlock(tp, &tp);
2582         passwordp = smb_ParseASCIIBlock(tp, &tp);
2583         tp = strrchr(pathp, '\\');
2584         if (!tp)
2585                 return CM_ERROR_BADSMB;
2586         strcpy(shareName, tp+1);
2587
2588         userp = smb_GetUser(vcp, inp);
2589
2590         lock_ObtainMutex(&vcp->mx);
2591         newTid = vcp->tidCounter++;
2592         lock_ReleaseMutex(&vcp->mx);
2593         
2594         tidp = smb_FindTID(vcp, newTid, SMB_FLAG_CREATE);
2595         shareFound = smb_FindShare(vcp, inp, shareName, &sharePath);
2596         if (!shareFound) {
2597                 smb_ReleaseTID(tidp);
2598                 return CM_ERROR_BADSHARENAME;
2599         }
2600         lock_ObtainMutex(&tidp->mx);
2601         tidp->userp = userp;
2602         tidp->pathname = sharePath;
2603         lock_ReleaseMutex(&tidp->mx);
2604         smb_ReleaseTID(tidp);
2605
2606         smb_SetSMBParm(rsp, 0, SMB_PACKETSIZE);
2607         smb_SetSMBParm(rsp, 1, newTid);
2608         smb_SetSMBDataLength(rsp, 0);
2609         
2610         osi_Log1(afsd_logp, "SMB tree connect created ID %d", newTid);
2611         return 0;
2612 }
2613
2614 unsigned char *smb_ParseDataBlock(unsigned char *inp, char **chainpp, int *lengthp)
2615 {
2616         int tlen;
2617
2618         if (*inp++ != 0x1) return NULL;
2619         tlen = inp[0] + (inp[1]<<8);
2620         inp += 2;               /* skip length field */
2621         
2622         if (chainpp) {
2623                 *chainpp = inp + tlen;
2624         }
2625         
2626         if (lengthp) *lengthp = tlen;
2627         
2628         return inp;
2629 }
2630
2631 /* set maskp to the mask part of the incoming path.
2632  * Mask is 11 bytes long (8.3 with the dot elided).
2633  * Returns true if succeeds with a valid name, otherwise it does
2634  * its best, but returns false.
2635  */
2636 int smb_Get8Dot3MaskFromPath(unsigned char *maskp, unsigned char *pathp)
2637 {
2638         char *tp;
2639         char *up;
2640         int i;
2641         int tc;
2642         int valid8Dot3;
2643
2644         /* starts off valid */
2645         valid8Dot3 = 1;
2646
2647         /* mask starts out all blanks */
2648         memset(maskp, ' ', 11);
2649
2650         /* find last backslash, or use whole thing if there is none */
2651         tp = strrchr(pathp, '\\');
2652         if (!tp) tp = pathp;
2653         else tp++;      /* skip slash */
2654         
2655         up = maskp;
2656
2657         /* names starting with a dot are illegal */
2658         if (*tp == '.') valid8Dot3 = 0;
2659
2660     for(i=0;; i++) {
2661                 tc = *tp++;
2662         if (tc == 0) return valid8Dot3;
2663         if (tc == '.' || tc == '"') break;
2664         if (i < 8) *up++ = tc;
2665         else valid8Dot3 = 0;
2666     }
2667         
2668     /* if we get here, tp point after the dot */
2669     up = maskp+8;       /* ext goes here */
2670     for(i=0;;i++) {
2671         tc = *tp++;
2672         if (tc == 0) return valid8Dot3;
2673
2674         /* too many dots */
2675         if (tc == '.' || tc == '"') valid8Dot3 = 0;
2676
2677         /* copy extension if not too long */
2678         if (i < 3) *up++ = tc;
2679         else valid8Dot3 = 0;
2680     }   
2681
2682     /* unreachable */
2683 }
2684
2685 int smb_Match8Dot3Mask(char *unixNamep, char *maskp)
2686 {
2687         char umask[11];
2688         int valid;
2689         int i;
2690         char tc1;
2691         char tc2;
2692         char *tp1;
2693         char *tp2;
2694         
2695         /* XXX redo this, calling smb_V3MatchMask with a converted mask */
2696
2697         valid = smb_Get8Dot3MaskFromPath(umask, unixNamep);
2698         if (!valid) return 0;
2699  
2700         /* otherwise, we have a valid 8.3 name; see if we have a match,
2701          * treating '?' as a wildcard in maskp (but not in the file name).
2702          */
2703         tp1 = umask;    /* real name, in mask format */
2704         tp2 = maskp;    /* mask, in mask format */
2705         for(i=0; i<11; i++) {
2706                 tc1 = *tp1++;   /* char from real name */
2707                 tc2 = *tp2++;   /* char from mask */
2708                 tc1 = (char) cm_foldUpper[(unsigned char)tc1];
2709                 tc2 = (char) cm_foldUpper[(unsigned char)tc2];
2710                 if (tc1 == tc2) continue;
2711                 if (tc2 == '?' && tc1 != ' ') continue;
2712                 if (tc2 == '>') continue;
2713                 return 0;
2714         }
2715
2716         /* we got a match */
2717         return 1;
2718 }
2719
2720 char *smb_FindMask(char *pathp)
2721 {
2722         char *tp;
2723         
2724         tp = strrchr(pathp, '\\');      /* find last slash */
2725
2726         if (tp) return tp+1;    /* skip the slash */
2727         else return pathp;      /* no slash, return the entire path */
2728 }
2729
2730 long smb_ReceiveCoreSearchVolume(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2731 {
2732         unsigned char *pathp;
2733         unsigned char *tp;
2734         unsigned char mask[11];
2735         unsigned char *statBlockp;
2736         unsigned char initStatBlock[21];
2737         int statLen;
2738         
2739         osi_Log0(afsd_logp, "SMB receive search volume");
2740
2741         /* pull pathname and stat block out of request */
2742         tp = smb_GetSMBData(inp, NULL);
2743         pathp = smb_ParseASCIIBlock(tp, (char **) &tp);
2744         osi_assert(pathp != NULL);
2745         statBlockp = smb_ParseVblBlock(tp, (char **) &tp, &statLen);
2746         osi_assert(statBlockp != NULL);
2747         if (statLen == 0) {
2748                 statBlockp = initStatBlock;
2749                 statBlockp[0] = 8;
2750         }
2751         
2752         /* for returning to caller */
2753         smb_Get8Dot3MaskFromPath(mask, pathp);
2754         
2755         smb_SetSMBParm(outp, 0, 1);             /* we're returning one entry */
2756         tp = smb_GetSMBData(outp, NULL);
2757         *tp++ = 5;
2758         *tp++ = 43;     /* bytes in a dir entry */
2759         *tp++ = 0;      /* high byte in counter */
2760         
2761         /* now marshall the dir entry, starting with the search status */
2762         *tp++ = statBlockp[0];          /* Reserved */
2763         memcpy(tp, mask, 11); tp += 11; /* FileName */
2764
2765         /* now pass back server use info, with 1st byte non-zero */
2766         *tp++ = 1;
2767         memset(tp, 0, 4); tp += 4;      /* reserved for server use */
2768         
2769         memcpy(tp, statBlockp+17, 4); tp += 4;  /* reserved for consumer */
2770         
2771         *tp++ = 0x8;            /* attribute: volume */
2772
2773         /* copy out time */
2774         *tp++ = 0;
2775         *tp++ = 0;
2776         
2777         /* copy out date */
2778         *tp++ = 18;
2779         *tp++ = 178;
2780         
2781         /* 4 byte file size */
2782         *tp++ = 0;
2783         *tp++ = 0;
2784         *tp++ = 0;
2785         *tp++ = 0;
2786
2787         /* finally, null-terminated 8.3 pathname, which we set to AFS */
2788         memset(tp, ' ', 13);
2789         strcpy(tp, "AFS");
2790         
2791         /* set the length of the data part of the packet to 43 + 3, for the dir
2792          * entry plus the 5 and the length fields.
2793          */
2794         smb_SetSMBDataLength(outp, 46);
2795         return 0;
2796 }
2797
2798 long smb_ApplyDirListPatches(smb_dirListPatch_t **dirPatchespp,
2799         cm_user_t *userp, cm_req_t *reqp)
2800 {
2801         long code;
2802         cm_scache_t *scp;
2803         char *dptr;
2804         long dosTime;
2805         u_short shortTemp;
2806         char attr;
2807         smb_dirListPatch_t *patchp;
2808         smb_dirListPatch_t *npatchp;
2809         
2810         for(patchp = *dirPatchespp; patchp; patchp =
2811                 (smb_dirListPatch_t *) osi_QNext(&patchp->q)) {
2812                 code = cm_GetSCache(&patchp->fid, &scp, userp, reqp);
2813                 if (code) continue;
2814                 lock_ObtainMutex(&scp->mx);
2815                 code = cm_SyncOp(scp, NULL, userp, reqp, 0,
2816                         CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
2817                 if (code) {
2818                         lock_ReleaseMutex(&scp->mx);
2819                         cm_ReleaseSCache(scp);
2820                         continue;
2821                 }
2822                 dptr = patchp->dptr;
2823
2824                 attr = smb_Attributes(scp);
2825                 *dptr++ = attr;
2826
2827         /* check hidden attribute (the flag is only ON when dot file hiding is on ) */
2828         if( patchp->flags & SMB_DIRLISTPATCH_DOTFILE )
2829             attr |= SMB_ATTR_HIDDEN;
2830
2831                 /* get dos time */
2832                 smb_SearchTimeFromUnixTime(&dosTime, scp->clientModTime);
2833                 
2834                 /* copy out time */
2835                 shortTemp = dosTime & 0xffff;
2836                 *((u_short *)dptr) = shortTemp;
2837                 dptr += 2;
2838
2839                 /* and copy out date */
2840                 shortTemp = (dosTime>>16) & 0xffff;
2841                 *((u_short *)dptr) = shortTemp;
2842                 dptr += 2;
2843                 
2844                 /* copy out file length */
2845                 *((u_long *)dptr) = scp->length.LowPart;
2846                 dptr += 4;
2847                 lock_ReleaseMutex(&scp->mx);
2848                 cm_ReleaseSCache(scp);
2849         }
2850         
2851         /* now free the patches */
2852         for(patchp = *dirPatchespp; patchp; patchp = npatchp) {
2853                 npatchp = (smb_dirListPatch_t *) osi_QNext(&patchp->q);
2854                 free(patchp);
2855         }
2856         
2857         /* and mark the list as empty */
2858         *dirPatchespp = NULL;
2859
2860         return code;
2861 }
2862
2863 long smb_ReceiveCoreSearchDir(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
2864 {
2865         int attribute;
2866         long nextCookie;
2867         char *tp;
2868         long code;
2869         char *pathp;
2870         cm_dirEntry_t *dep;
2871         int maxCount;
2872         smb_dirListPatch_t *dirListPatchesp;
2873         smb_dirListPatch_t *curPatchp;
2874         int dataLength;
2875         cm_buf_t *bufferp;
2876         long temp;
2877         osi_hyper_t dirLength;
2878         osi_hyper_t bufferOffset;
2879         osi_hyper_t curOffset;
2880         osi_hyper_t thyper;
2881         unsigned char *inCookiep;
2882         smb_dirSearch_t *dsp;
2883         cm_scache_t *scp;
2884         long entryInDir;
2885         long entryInBuffer;
2886         unsigned long clientCookie;
2887         cm_pageHeader_t *pageHeaderp;
2888         cm_user_t *userp = NULL;
2889         int slotInPage;
2890         char shortName[13];
2891         char *actualName;
2892         char *shortNameEnd;
2893         char mask[11];
2894         int returnedNames;
2895         long nextEntryCookie;
2896         int numDirChunks;               /* # of 32 byte dir chunks in this entry */
2897         char resByte;                   /* reserved byte from the cookie */
2898         char *op;                       /* output data ptr */
2899         char *origOp;                   /* original value of op */
2900         cm_space_t *spacep;             /* for pathname buffer */
2901         int starPattern;
2902         int rootPath = 0;
2903         int caseFold;
2904         char *tidPathp;
2905         cm_req_t req;
2906         cm_fid_t fid;
2907         int fileType;
2908
2909         cm_InitReq(&req);
2910
2911         maxCount = smb_GetSMBParm(inp, 0);
2912
2913         dirListPatchesp = NULL;
2914         
2915         caseFold = CM_FLAG_CASEFOLD;
2916
2917         tp = smb_GetSMBData(inp, NULL);
2918         pathp = smb_ParseASCIIBlock(tp, &tp);
2919         inCookiep = smb_ParseVblBlock(tp, &tp, &dataLength);
2920         
2921         /* bail out if request looks bad */
2922         if (!tp || !pathp) {
2923                 return CM_ERROR_BADSMB;
2924         }
2925
2926         /* We can handle long names */
2927         if (vcp->flags & SMB_VCFLAG_USENT)
2928                 ((smb_t *)outp)->flg2 |= 0x40;  /* IS_LONG_NAME */
2929         
2930         /* make sure we got a whole search status */
2931         if (dataLength < 21) {
2932                 nextCookie = 0;         /* start at the beginning of the dir */
2933                 resByte = 0;
2934                 clientCookie = 0;
2935                 attribute = smb_GetSMBParm(inp, 1);
2936
2937                 /* handle volume info in another function */
2938                 if (attribute & 0x8)
2939                         return smb_ReceiveCoreSearchVolume(vcp, inp, outp);
2940
2941                 osi_Log2(afsd_logp, "SMB receive search dir count %d [%s]",
2942                          maxCount, osi_LogSaveString(afsd_logp, pathp));
2943
2944                 if (*pathp == 0) {      /* null pathp, treat as root dir */
2945                         if (!(attribute & SMB_ATTR_DIRECTORY))  /* exclude dirs */
2946                                 return CM_ERROR_NOFILES;
2947                         rootPath = 1;
2948                 }
2949
2950                 dsp = smb_NewDirSearch(0);
2951                 dsp->attribute = attribute;
2952                 smb_Get8Dot3MaskFromPath(mask, pathp);
2953                 memcpy(dsp->mask, mask, 11);
2954
2955                 /* track if this is likely to match a lot of entries */
2956                 if (smb_IsStarMask(mask)) starPattern = 1;
2957                 else starPattern = 0;
2958         }
2959         else {
2960                 /* pull the next cookie value out of the search status block */
2961                 nextCookie = inCookiep[13] + (inCookiep[14]<<8) + (inCookiep[15]<<16)
2962                         + (inCookiep[16]<<24);
2963                 dsp = smb_FindDirSearch(inCookiep[12]);
2964                 if (!dsp) {
2965                         /* can't find dir search status; fatal error */
2966                         return CM_ERROR_BADFD;
2967                 }
2968                 attribute = dsp->attribute;
2969                 resByte = inCookiep[0];
2970
2971                 /* copy out client cookie, in host byte order.  Don't bother
2972                  * interpreting it, since we're just passing it through, anyway.
2973                  */
2974                 memcpy(&clientCookie, &inCookiep[17], 4);
2975
2976                 memcpy(mask, dsp->mask, 11);
2977
2978                 /* assume we're doing a star match if it has continued for more
2979                  * than one call.
2980                  */
2981                 starPattern = 1;
2982         }
2983
2984         osi_Log3(afsd_logp, "SMB dir search cookie 0x%x, connection %d, attr 0x%x",
2985                 nextCookie, dsp->cookie, attribute);
2986
2987         userp = smb_GetUser(vcp, inp);
2988
2989         /* try to get the vnode for the path name next */
2990         lock_ObtainMutex(&dsp->mx);
2991         if (dsp->scp) {
2992                 scp = dsp->scp;
2993                 cm_HoldSCache(scp);
2994                 code = 0;
2995         }
2996         else {
2997                 spacep = inp->spacep;
2998                 smb_StripLastComponent(spacep->data, NULL, pathp);
2999                 lock_ReleaseMutex(&dsp->mx);
3000                 tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3001                 code = cm_NameI(cm_rootSCachep, spacep->data,
3002                         caseFold | CM_FLAG_FOLLOW, userp, tidPathp, &req, &scp);
3003                 lock_ObtainMutex(&dsp->mx);
3004                 if (code == 0) {
3005                         if (dsp->scp != 0) cm_ReleaseSCache(dsp->scp);
3006                         dsp->scp = scp;
3007                         /* we need one hold for the entry we just stored into,
3008                          * and one for our own processing.  When we're done with this
3009                          * function, we'll drop the one for our own processing.
3010                          * We held it once from the namei call, and so we do another hold
3011                          * now.
3012                          */
3013                         cm_HoldSCache(scp);
3014                         lock_ObtainMutex(&scp->mx);
3015                         if ((scp->flags & CM_SCACHEFLAG_BULKSTATTING) == 0
3016                             && LargeIntegerGreaterOrEqualToZero(scp->bulkStatProgress)) {
3017                                 scp->flags |= CM_SCACHEFLAG_BULKSTATTING;
3018                                 dsp->flags |= SMB_DIRSEARCH_BULKST;
3019                         }
3020                         lock_ReleaseMutex(&scp->mx);
3021                 }
3022         }
3023         lock_ReleaseMutex(&dsp->mx);
3024         if (code) {
3025                 cm_ReleaseUser(userp);
3026                 smb_DeleteDirSearch(dsp);
3027                 smb_ReleaseDirSearch(dsp);
3028                 return code;
3029         }
3030
3031         /* reserves space for parameter; we'll adjust it again later to the
3032          * real count of the # of entries we returned once we've actually
3033          * assembled the directory listing.
3034          */
3035         smb_SetSMBParm(outp, 0, 0);
3036         
3037         /* get the directory size */
3038         lock_ObtainMutex(&scp->mx);
3039         code = cm_SyncOp(scp, NULL, userp, &req, 0,
3040                 CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
3041         if (code) {
3042                 lock_ReleaseMutex(&scp->mx);
3043                 cm_ReleaseSCache(scp);
3044                 cm_ReleaseUser(userp);
3045                 smb_DeleteDirSearch(dsp);
3046                 smb_ReleaseDirSearch(dsp);
3047                 return code;
3048         }
3049         
3050         dirLength = scp->length;
3051         bufferp = NULL;
3052         bufferOffset.LowPart = bufferOffset.HighPart = 0;
3053         curOffset.HighPart = 0;
3054         curOffset.LowPart = nextCookie;
3055         origOp = op = smb_GetSMBData(outp, NULL);
3056         /* and write out the basic header */
3057         *op++ = 5;              /* variable block */
3058         op += 2;                /* skip vbl block length; we'll fill it in later */
3059         code = 0;
3060         returnedNames = 0;
3061         while (1) {
3062                 /* make sure that curOffset.LowPart doesn't point to the first
3063                  * 32 bytes in the 2nd through last dir page, and that it doesn't
3064                  * point at the first 13 32-byte chunks in the first dir page,
3065                  * since those are dir and page headers, and don't contain useful
3066                  * information.
3067                  */
3068                 temp = curOffset.LowPart & (2048-1);
3069                 if (curOffset.HighPart == 0 && curOffset.LowPart < 2048) {
3070                         /* we're in the first page */
3071                         if (temp < 13*32) temp = 13*32;
3072                 }
3073                 else {
3074                         /* we're in a later dir page */
3075                         if (temp < 32) temp = 32;
3076                 }
3077                 
3078                 /* make sure the low order 5 bits are zero */
3079                 temp &= ~(32-1);
3080                 
3081                 /* now put temp bits back ito curOffset.LowPart */
3082                 curOffset.LowPart &= ~(2048-1);
3083                 curOffset.LowPart |= temp;
3084
3085                 /* check if we've returned all the names that will fit in the
3086                  * response packet.
3087                  */
3088                 if (returnedNames >= maxCount) break;
3089                 
3090                 /* check if we've passed the dir's EOF */
3091                 if (LargeIntegerGreaterThanOrEqualTo(curOffset, dirLength)) break;
3092                 
3093                 /* see if we can use the bufferp we have now; compute in which page
3094                  * the current offset would be, and check whether that's the offset
3095                  * of the buffer we have.  If not, get the buffer.
3096                  */
3097                 thyper.HighPart = curOffset.HighPart;
3098                 thyper.LowPart = curOffset.LowPart & ~(buf_bufferSize-1);
3099                 if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
3100                         /* wrong buffer */
3101                         if (bufferp) {
3102                                 buf_Release(bufferp);
3103                                 bufferp = NULL;
3104                         }
3105                         lock_ReleaseMutex(&scp->mx);
3106                         lock_ObtainRead(&scp->bufCreateLock);
3107                         code = buf_Get(scp, &thyper, &bufferp);
3108                         lock_ReleaseRead(&scp->bufCreateLock);
3109
3110                         /* now, if we're doing a star match, do bulk fetching of all of 
3111                          * the status info for files in the dir.
3112                          */
3113                         if (starPattern) {
3114                                 smb_ApplyDirListPatches(&dirListPatchesp, userp,
3115                                                         &req);
3116                                 if ((dsp->flags & SMB_DIRSEARCH_BULKST)
3117                                     && LargeIntegerGreaterThanOrEqualTo(thyper, 
3118                                                                         scp->bulkStatProgress)) {
3119                                   /* Don't bulk stat if risking timeout */
3120                                   int now = GetCurrentTime();
3121                                   if (now - req.startTime > 5000) {
3122                                     scp->bulkStatProgress = thyper;
3123                                     scp->flags &= ~CM_SCACHEFLAG_BULKSTATTING;
3124                                     dsp->flags &= ~SMB_DIRSEARCH_BULKST;
3125                                   } else
3126                                     cm_TryBulkStat(scp, &thyper,
3127                                                    userp, &req);
3128                                 }
3129                         }
3130
3131                         lock_ObtainMutex(&scp->mx);
3132                         if (code) break;
3133                         bufferOffset = thyper;
3134
3135                         /* now get the data in the cache */
3136                         while (1) {
3137                                 code = cm_SyncOp(scp, bufferp, userp, &req,
3138                                         PRSFS_LOOKUP,
3139                                         CM_SCACHESYNC_NEEDCALLBACK
3140                                         | CM_SCACHESYNC_READ);
3141                                 if (code) break;
3142                                 
3143                                 if (cm_HaveBuffer(scp, bufferp, 0)) break;
3144                                 
3145                                 /* otherwise, load the buffer and try again */
3146                                 code = cm_GetBuffer(scp, bufferp, NULL, userp,
3147                                                     &req);
3148                                 if (code) break;
3149                         }
3150                         if (code) {
3151                                 buf_Release(bufferp);
3152                                 bufferp = NULL;
3153                                 break;
3154                         }
3155                 }       /* if (wrong buffer) ... */
3156                 
3157                 /* now we have the buffer containing the entry we're interested in; copy
3158                  * it out if it represents a non-deleted entry.
3159                  */
3160                 entryInDir = curOffset.LowPart & (2048-1);
3161                 entryInBuffer = curOffset.LowPart & (buf_bufferSize - 1);
3162
3163                 /* page header will help tell us which entries are free.  Page header
3164                  * can change more often than once per buffer, since AFS 3 dir page size
3165                  * may be less than (but not more than a buffer package buffer.
3166                  */
3167                 temp = curOffset.LowPart & (buf_bufferSize - 1);  /* only look intra-buffer */
3168                 temp &= ~(2048 - 1);    /* turn off intra-page bits */
3169                 pageHeaderp = (cm_pageHeader_t *) (bufferp->datap + temp);
3170
3171                 /* now determine which entry we're looking at in the page.  If it is
3172                  * free (there's a free bitmap at the start of the dir), we should
3173                  * skip these 32 bytes.
3174                  */
3175                 slotInPage = (entryInDir & 0x7e0) >> 5;
3176                 if (!(pageHeaderp->freeBitmap[slotInPage>>3] & (1 << (slotInPage & 0x7)))) {
3177                         /* this entry is free */
3178                         numDirChunks = 1;               /* only skip this guy */
3179                         goto nextEntry;
3180                 }
3181
3182                 tp = bufferp->datap + entryInBuffer;
3183                 dep = (cm_dirEntry_t *) tp;             /* now points to AFS3 dir entry */
3184
3185                 /* while we're here, compute the next entry's location, too,
3186                  * since we'll need it when writing out the cookie into the dir
3187                  * listing stream.
3188                  *
3189                  * XXXX Probably should do more sanity checking.
3190                  */
3191                 numDirChunks = cm_NameEntries(dep->name, NULL);
3192                 
3193                 /* compute the offset of the cookie representing the next entry */
3194                 nextEntryCookie = curOffset.LowPart + (CM_DIR_CHUNKSIZE * numDirChunks);
3195
3196                 /* Compute 8.3 name if necessary */
3197                 actualName = dep->name;
3198                 if (dep->fid.vnode != 0 && !cm_Is8Dot3(actualName)) {
3199                         cm_Gen8Dot3Name(dep, shortName, &shortNameEnd);
3200                         actualName = shortName;
3201                 }
3202
3203             if (dep->fid.vnode != 0 && smb_Match8Dot3Mask(actualName, mask)) {
3204                 /* this is one of the entries to use: it is not deleted
3205                  * and it matches the star pattern we're looking for.
3206                  */
3207
3208                 /* Eliminate entries that don't match requested
3209                    attributes */
3210                  
3211                 /* no hidden files */
3212                 if(smb_hideDotFiles && !(dsp->attribute & SMB_ATTR_HIDDEN) && smb_IsDotFile(actualName))
3213                     goto nextEntry;
3214                 
3215                 if (!(dsp->attribute & SMB_ATTR_DIRECTORY))  /* no directories */
3216                 {
3217                            /* We have already done the cm_TryBulkStat above */
3218                            fid.cell = scp->fid.cell;
3219                            fid.volume = scp->fid.volume;
3220                            fid.vnode = ntohl(dep->fid.vnode);
3221                            fid.unique = ntohl(dep->fid.unique);
3222                            fileType = cm_FindFileType(&fid);
3223                            osi_Log2(afsd_logp, "smb_ReceiveCoreSearchDir: file %s "
3224                                     "has filetype %d", dep->name,
3225                                     fileType);
3226                            if (fileType == CM_SCACHETYPE_DIRECTORY)
3227                               goto nextEntry;
3228                         }
3229
3230                         *op++ = resByte;
3231                         memcpy(op, mask, 11); op += 11;
3232                         *op++ = (char) dsp->cookie;     /* they say it must be non-zero */
3233                         *op++ = nextEntryCookie & 0xff;
3234                         *op++ = (nextEntryCookie>>8) & 0xff;
3235                         *op++ = (nextEntryCookie>>16) & 0xff;
3236                         *op++ = (nextEntryCookie>>24) & 0xff;
3237                         memcpy(op, &clientCookie, 4); op += 4;
3238                         
3239                         /* now we emit the attribute.  This is sort of tricky,
3240                          * since we need to really stat the file to find out
3241                          * what type of entry we've got.  Right now, we're
3242                          * copying out data from a buffer, while holding the
3243                          * scp locked, so it isn't really convenient to stat
3244                          * something now.  We'll put in a place holder now,
3245                          * and make a second pass before returning this to get
3246                          * the real attributes.  So, we just skip the data for
3247                          * now, and adjust it later.  We allocate a patch
3248                          * record to make it easy to find this point later.
3249                          * The replay will happen at a time when it is safe to
3250                          * unlock the directory.
3251                          */
3252                 curPatchp = malloc(sizeof(*curPatchp));
3253                 osi_QAdd((osi_queue_t **) &dirListPatchesp, &curPatchp->q);
3254                 curPatchp->dptr = op;
3255                 curPatchp->fid.cell = scp->fid.cell;
3256                 curPatchp->fid.volume = scp->fid.volume;
3257                 curPatchp->fid.vnode = ntohl(dep->fid.vnode);
3258                 curPatchp->fid.unique = ntohl(dep->fid.unique);
3259
3260                 /* do hidden attribute here since name won't be around when applying
3261                  * dir list patches
3262                  */
3263
3264                 if ( smb_hideDotFiles && smb_IsDotFile(actualName) )
3265                     curPatchp->flags = SMB_DIRLISTPATCH_DOTFILE;
3266                 else
3267                     curPatchp->flags = 0;
3268
3269                 op += 9;        /* skip attr, time, date and size */
3270                         
3271                         /* zero out name area.  The spec says to pad with
3272                          * spaces, but Samba doesn't, and neither do we.
3273                          */
3274                         memset(op, 0, 13);
3275
3276                         /* finally, we get to copy out the name; we know that
3277                          * it fits in 8.3 or the pattern wouldn't match, but it
3278                          * never hurts to be sure.
3279                          */
3280                         strncpy(op, actualName, 13);
3281
3282                         /* Uppercase if requested by client */
3283                         if ((((smb_t *)inp)->flg2 & 1) == 0)
3284                                 _strupr(op);
3285
3286                         op += 13;
3287
3288                         /* now, adjust the # of entries copied */
3289                         returnedNames++;
3290                 }       /* if we're including this name */
3291                 
3292 nextEntry:
3293                 /* and adjust curOffset to be where the new cookie is */
3294                 thyper.HighPart = 0;
3295                 thyper.LowPart = CM_DIR_CHUNKSIZE * numDirChunks;
3296                 curOffset = LargeIntegerAdd(thyper, curOffset);
3297         }               /* while copying data for dir listing */
3298
3299         /* release the mutex */
3300         lock_ReleaseMutex(&scp->mx);
3301         if (bufferp) buf_Release(bufferp);
3302
3303         /* apply and free last set of patches; if not doing a star match, this
3304          * will be empty, but better safe (and freeing everything) than sorry.
3305          */
3306         smb_ApplyDirListPatches(&dirListPatchesp, userp, &req);
3307
3308         /* special return code for unsuccessful search */
3309         if (code == 0 && dataLength < 21 && returnedNames == 0)
3310                 code = CM_ERROR_NOFILES;
3311
3312         osi_Log2(afsd_logp, "SMB search dir done, %d names, code %d",
3313                  returnedNames, code);
3314
3315         if (code != 0) {
3316                 smb_DeleteDirSearch(dsp);
3317                 smb_ReleaseDirSearch(dsp);
3318                 cm_ReleaseSCache(scp);
3319                 cm_ReleaseUser(userp);
3320                 return code;
3321         }
3322
3323         /* finalize the output buffer */
3324         smb_SetSMBParm(outp, 0, returnedNames);
3325         temp = (long) (op - origOp);
3326         smb_SetSMBDataLength(outp, temp);
3327
3328         /* the data area is a variable block, which has a 5 (already there)
3329          * followed by the length of the # of data bytes.  We now know this to
3330          * be "temp," although that includes the 3 bytes of vbl block header.
3331          * Deduct for them and fill in the length field.
3332          */
3333         temp -= 3;              /* deduct vbl block info */
3334         osi_assert(temp == (43 * returnedNames));
3335         origOp[1] = temp & 0xff;
3336         origOp[2] = (temp>>8) & 0xff;
3337         if (returnedNames == 0) smb_DeleteDirSearch(dsp);
3338         smb_ReleaseDirSearch(dsp);
3339         cm_ReleaseSCache(scp);
3340         cm_ReleaseUser(userp);
3341         return code;
3342 }
3343
3344 /* verify that this is a valid path to a directory.  I don't know why they
3345  * don't use the get file attributes call.
3346  */
3347 long smb_ReceiveCoreCheckPath(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3348 {
3349         char *pathp;
3350         long code;
3351         cm_scache_t *rootScp;
3352         cm_scache_t *newScp;
3353         cm_user_t *userp;
3354         unsigned int attrs;
3355         int caseFold;
3356         char *tidPathp;
3357         cm_req_t req;
3358
3359         cm_InitReq(&req);
3360
3361         pathp = smb_GetSMBData(inp, NULL);
3362         pathp = smb_ParseASCIIBlock(pathp, NULL);
3363         osi_Log1(afsd_logp, "SMB receive check path %s",
3364                         osi_LogSaveString(afsd_logp, pathp));
3365         
3366         if (!pathp) {
3367                 return CM_ERROR_BADFD;
3368         }
3369         
3370         rootScp = cm_rootSCachep;
3371         
3372         userp = smb_GetUser(vcp, inp);
3373
3374         caseFold = CM_FLAG_CASEFOLD;
3375
3376         tidPathp = smb_GetTIDPath(vcp, ((smb_t *)inp)->tid);
3377         code = cm_NameI(rootScp, pathp,
3378                         caseFold | CM_FLAG_FOLLOW | CM_FLAG_CHECKPATH,
3379                         userp, tidPathp, &req, &newScp);
3380
3381         if (code) {
3382                 cm_ReleaseUser(userp);
3383                 return code;
3384         }
3385         
3386         /* now lock the vnode with a callback; returns with newScp locked */
3387         lock_ObtainMutex(&newScp->mx);
3388         code = cm_SyncOp(newScp, NULL, userp, &req, PRSFS_LOOKUP,
3389                 CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
3390         if (code && code != CM_ERROR_NOACCESS) {
3391                 lock_ReleaseMutex(&newScp->mx);
3392                 cm_ReleaseSCache(newScp);
3393                 cm_ReleaseUser(userp);
3394                 return code;
3395         }
3396
3397         attrs = smb_Attributes(newScp);
3398
3399         if (!(attrs & 0x10))
3400                 code = CM_ERROR_NOTDIR;
3401
3402         lock_ReleaseMutex(&newScp->mx);
3403         
3404         cm_ReleaseSCache(newScp);
3405         cm_ReleaseUser(userp);
3406         return code;
3407 }
3408
3409 long smb_ReceiveCoreSetFileAttributes(smb_vc_t *vcp, smb_packet_t *inp, smb_packet_t *outp)
3410 {
3411         char *pathp;
3412         long code;
3413         cm_scache_t *rootScp;
3414         unsigned short attribute;
3415         cm_attr_t attr;
3416         cm_scache_t *newScp;
3417         long dosTime;
3418         cm_user_t *userp;
3419         int caseFold;
3420         char *tidPathp;
3421         cm_req_t req;
3422
3423         cm_InitReq(&req);
3424
3425         /* decode basic attributes we're passed */
3426         attribute = smb_GetSMBParm(inp, 0);
3427         dosTime = smb_GetSMBParm(inp, 1) | (smb_GetSMBParm(inp, 2) << 16);
3428
3429         pathp = smb_GetSMBData(inp, NULL);
3430         pathp = smb_ParseASCIIBlock(pathp, NULL);
3431         
3432         if (!pathp) {
3433                 return CM_ERROR_BADSMB;
3434         }
3435         
3436         osi_Log2(afsd_logp, "SMB receive setfile attributes time %d, attr 0x%x",
3437                 dosTime, attribute);
3438
3439         rootScp = cm_rootSCachep;
3440