This is *not* a big change (although it looks like one).
[samba.git] / source / smbd / trans2.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB transaction2 handling
5    Copyright (C) Jeremy Allison 1994-1998
6
7    Extensively modified by Andrew Tridgell, 1995
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "trans2.h"
26
27 extern int DEBUGLEVEL;
28 extern int Protocol;
29 extern connection_struct Connections[];
30 extern files_struct Files[];
31 extern BOOL case_sensitive;
32 extern int Client;
33 extern int oplock_sock;
34 extern int smb_read_error;
35
36 /****************************************************************************
37   Send the required number of replies back.
38   We assume all fields other than the data fields are
39   set correctly for the type of call.
40   HACK ! Always assumes smb_setup field is zero.
41 ****************************************************************************/
42 static int send_trans2_replies(char *outbuf, int bufsize, char *params, 
43                          int paramsize, char *pdata, int datasize)
44 {
45   /* As we are using a protocol > LANMAN1 then the max_send
46      variable must have been set in the sessetupX call.
47      This takes precedence over the max_xmit field in the
48      global struct. These different max_xmit variables should
49      be merged as this is now too confusing */
50
51   extern int max_send;
52   int data_to_send = datasize;
53   int params_to_send = paramsize;
54   int useable_space;
55   char *pp = params;
56   char *pd = pdata;
57   int params_sent_thistime, data_sent_thistime, total_sent_thistime;
58   int alignment_offset = 1;
59
60   /* Initially set the wcnt area to be 10 - this is true for all
61      trans2 replies */
62   set_message(outbuf,10,0,True);
63
64   /* If there genuinely are no parameters or data to send just send
65      the empty packet */
66   if(params_to_send == 0 && data_to_send == 0)
67     {
68       send_smb(Client,outbuf);
69       return 0;
70     }
71
72   /* Space is bufsize minus Netbios over TCP header minus SMB header */
73   /* The alignment_offset is to align the param and data bytes on an even byte
74      boundary. NT 4.0 Beta needs this to work correctly. */
75   useable_space = bufsize - ((smb_buf(outbuf)+alignment_offset) - outbuf);
76   /* useable_space can never be more than max_send minus the
77      alignment offset. */
78   useable_space = MIN(useable_space, max_send - alignment_offset);
79
80   while( params_to_send || data_to_send)
81     {
82       /* Calculate whether we will totally or partially fill this packet */
83       total_sent_thistime = params_to_send + data_to_send + alignment_offset;
84       /* We can never send more than useable_space */
85       total_sent_thistime = MIN(total_sent_thistime, useable_space);
86
87       set_message(outbuf, 10, total_sent_thistime, True);
88
89       /* Set total params and data to be sent */
90       SSVAL(outbuf,smb_tprcnt,paramsize);
91       SSVAL(outbuf,smb_tdrcnt,datasize);
92
93       /* Calculate how many parameters and data we can fit into
94          this packet. Parameters get precedence */
95
96       params_sent_thistime = MIN(params_to_send,useable_space);
97       data_sent_thistime = useable_space - params_sent_thistime;
98       data_sent_thistime = MIN(data_sent_thistime,data_to_send);
99
100       SSVAL(outbuf,smb_prcnt, params_sent_thistime);
101       if(params_sent_thistime == 0)
102         {
103           SSVAL(outbuf,smb_proff,0);
104           SSVAL(outbuf,smb_prdisp,0);
105         } else {
106           /* smb_proff is the offset from the start of the SMB header to the
107              parameter bytes, however the first 4 bytes of outbuf are
108              the Netbios over TCP header. Thus use smb_base() to subtract
109              them from the calculation */
110           SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
111           /* Absolute displacement of param bytes sent in this packet */
112           SSVAL(outbuf,smb_prdisp,pp - params);
113         }
114
115       SSVAL(outbuf,smb_drcnt, data_sent_thistime);
116       if(data_sent_thistime == 0)
117         {
118           SSVAL(outbuf,smb_droff,0);
119           SSVAL(outbuf,smb_drdisp, 0);
120         } else {
121           /* The offset of the data bytes is the offset of the
122              parameter bytes plus the number of parameters being sent this time */
123           SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - 
124                                   smb_base(outbuf)) + params_sent_thistime);
125           SSVAL(outbuf,smb_drdisp, pd - pdata);
126         }
127
128       /* Copy the param bytes into the packet */
129       if(params_sent_thistime)
130         memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
131       /* Copy in the data bytes */
132       if(data_sent_thistime)
133         memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime,pd,data_sent_thistime);
134
135       DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
136                params_sent_thistime, data_sent_thistime, useable_space));
137       DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
138                params_to_send, data_to_send, paramsize, datasize));
139
140       /* Send the packet */
141       send_smb(Client,outbuf);
142
143       pp += params_sent_thistime;
144       pd += data_sent_thistime;
145
146       params_to_send -= params_sent_thistime;
147       data_to_send -= data_sent_thistime;
148
149       /* Sanity check */
150       if(params_to_send < 0 || data_to_send < 0)
151         {
152           DEBUG(2,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
153                    params_to_send, data_to_send));
154           return -1;
155         }
156     }
157
158   return 0;
159 }
160
161
162 /****************************************************************************
163   reply to a TRANSACT2_OPEN
164 ****************************************************************************/
165 static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum, 
166                     char **pparams, char **ppdata)
167 {
168   char *params = *pparams;
169   int16 open_mode = SVAL(params, 2);
170   int16 open_attr = SVAL(params,6);
171   BOOL oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
172 #if 0
173   BOOL return_additional_info = BITSETW(params,0);
174   int16 open_sattr = SVAL(params, 4);
175   time_t open_time = make_unix_date3(params+8);
176 #endif
177   int16 open_ofun = SVAL(params,12);
178   int32 open_size = IVAL(params,14);
179   char *pname = &params[28];
180   int16 namelen = strlen(pname)+1;
181
182   pstring fname;
183   int fnum = -1;
184   int unixmode;
185   int size=0,fmode=0,mtime=0,rmode;
186   int32 inode = 0;
187   struct stat sbuf;
188   int smb_action = 0;
189   BOOL bad_path = False;
190
191   StrnCpy(fname,pname,namelen);
192
193   DEBUG(3,("trans2open %s cnum=%d mode=%d attr=%d ofun=%d size=%d\n",
194            fname,cnum,open_mode, open_attr, open_ofun, open_size));
195
196   /* XXXX we need to handle passed times, sattr and flags */
197
198   unix_convert(fname,cnum,0,&bad_path);
199     
200   fnum = find_free_file();
201   if (fnum < 0)
202     return(ERROR(ERRSRV,ERRnofids));
203
204   if (!check_name(fname,cnum))
205   {
206     if((errno == ENOENT) && bad_path)
207     {
208       unix_ERR_class = ERRDOS;
209       unix_ERR_code = ERRbadpath;
210     }
211     Files[fnum].reserved = False;
212     return(UNIXERROR(ERRDOS,ERRnoaccess));
213   }
214
215   unixmode = unix_mode(cnum,open_attr | aARCH);
216       
217       
218   open_file_shared(fnum,cnum,fname,open_mode,open_ofun,unixmode,
219                    oplock_request, &rmode,&smb_action);
220       
221   if (!Files[fnum].open)
222   {
223     if((errno == ENOENT) && bad_path)
224     {
225       unix_ERR_class = ERRDOS;
226       unix_ERR_code = ERRbadpath;
227     }
228     Files[fnum].reserved = False;
229     return(UNIXERROR(ERRDOS,ERRnoaccess));
230   }
231
232   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
233     close_file(fnum,False);
234     return(ERROR(ERRDOS,ERRnoaccess));
235   }
236     
237   size = sbuf.st_size;
238   fmode = dos_mode(cnum,fname,&sbuf);
239   mtime = sbuf.st_mtime;
240   inode = sbuf.st_ino;
241   if (fmode & aDIR) {
242     close_file(fnum,False);
243     return(ERROR(ERRDOS,ERRnoaccess));
244   }
245
246   /* Realloc the size of parameters and data we will return */
247   params = *pparams = Realloc(*pparams, 28);
248   if(params == NULL)
249     return(ERROR(ERRDOS,ERRnomem));
250
251   bzero(params,28);
252   SSVAL(params,0,fnum);
253   SSVAL(params,2,fmode);
254   put_dos_date2(params,4, mtime);
255   SIVAL(params,8, size);
256   SSVAL(params,12,rmode);
257
258   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
259     smb_action |= EXTENDED_OPLOCK_GRANTED;
260   }
261
262   SSVAL(params,18,smb_action);
263   SIVAL(params,20,inode);
264  
265   /* Send the required number of replies */
266   send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0);
267
268   return -1;
269 }
270
271 /****************************************************************************
272   get a level dependent lanman2 dir entry.
273 ****************************************************************************/
274 static int get_lanman2_dir_entry(int cnum,char *path_mask,int dirtype,int info_level,
275                                  int requires_resume_key,
276                                  BOOL dont_descend,char **ppdata, 
277                                  char *base_data, int space_remaining, 
278                                  BOOL *out_of_space,
279                                  int *last_name_off)
280 {
281   char *dname;
282   BOOL found = False;
283   struct stat sbuf;
284   pstring mask;
285   pstring pathreal;
286   pstring fname;
287   BOOL matched;
288   char *p, *pdata = *ppdata;
289   int reskey=0, prev_dirpos=0;
290   int mode=0;
291   uint32 size=0,len;
292   uint32 mdate=0, adate=0, cdate=0;
293   char *nameptr;
294   BOOL isrootdir = (strequal(Connections[cnum].dirpath,"./") ||
295                     strequal(Connections[cnum].dirpath,".") ||
296                     strequal(Connections[cnum].dirpath,"/"));
297   BOOL was_8_3;
298   int nt_extmode; /* Used for NT connections instead of mode */
299   BOOL needslash = ( Connections[cnum].dirpath[strlen(Connections[cnum].dirpath) -1] != '/');
300
301   *fname = 0;
302   *out_of_space = False;
303
304   if (!Connections[cnum].dirptr)
305     return(False);
306
307   p = strrchr(path_mask,'/');
308   if(p != NULL)
309     {
310       if(p[1] == '\0')
311         strcpy(mask,"*.*");
312       else
313         pstrcpy(mask, p+1);
314     }
315   else
316     pstrcpy(mask, path_mask);
317
318   while (!found)
319     {
320       /* Needed if we run out of space */
321       prev_dirpos = TellDir(Connections[cnum].dirptr);
322       dname = ReadDirName(Connections[cnum].dirptr);
323
324       reskey = TellDir(Connections[cnum].dirptr);
325
326       DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%x now at offset %d\n",
327                Connections[cnum].dirptr,TellDir(Connections[cnum].dirptr)));
328       
329       if (!dname) 
330         return(False);
331
332       matched = False;
333
334       pstrcpy(fname,dname);      
335
336       if(mask_match(fname, mask, case_sensitive, True))
337         {
338           BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
339           if (dont_descend && !isdots)
340             continue;
341           
342           if (isrootdir && isdots)
343             continue;
344
345           pstrcpy(pathreal,Connections[cnum].dirpath);
346           if(needslash)
347             strcat(pathreal,"/");
348           strcat(pathreal,dname);
349           if (sys_stat(pathreal,&sbuf) != 0) 
350             {
351               DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",pathreal,strerror(errno)));
352               continue;
353             }
354
355           mode = dos_mode(cnum,pathreal,&sbuf);
356
357           if (!dir_check_ftype(cnum,mode,&sbuf,dirtype)) {
358             DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
359             continue;
360           }
361
362           size = sbuf.st_size;
363           mdate = sbuf.st_mtime;
364           adate = sbuf.st_atime;
365           cdate = sbuf.st_ctime;
366           if(mode & aDIR)
367             size = 0;
368
369           DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
370           
371           found = True;
372         }
373     }
374
375   name_map_mangle(fname,False,SNUM(cnum));
376
377   p = pdata;
378   nameptr = p;
379
380   nt_extmode = mode ? mode : NT_FILE_ATTRIBUTE_NORMAL;
381
382   switch (info_level)
383     {
384     case 1:
385       if(requires_resume_key) {
386         SIVAL(p,0,reskey);
387         p += 4;
388       }
389       put_dos_date2(p,l1_fdateCreation,cdate);
390       put_dos_date2(p,l1_fdateLastAccess,adate);
391       put_dos_date2(p,l1_fdateLastWrite,mdate);
392       SIVAL(p,l1_cbFile,size);
393       SIVAL(p,l1_cbFileAlloc,ROUNDUP(size,1024));
394       SSVAL(p,l1_attrFile,mode);
395       SCVAL(p,l1_cchName,strlen(fname));
396       strcpy(p + l1_achName, fname);
397       nameptr = p + l1_achName;
398       p += l1_achName + strlen(fname) + 1;
399       break;
400
401     case 2:
402       /* info_level 2 */
403       if(requires_resume_key) {
404         SIVAL(p,0,reskey);
405         p += 4;
406       }
407       put_dos_date2(p,l2_fdateCreation,cdate);
408       put_dos_date2(p,l2_fdateLastAccess,adate);
409       put_dos_date2(p,l2_fdateLastWrite,mdate);
410       SIVAL(p,l2_cbFile,size);
411       SIVAL(p,l2_cbFileAlloc,ROUNDUP(size,1024));
412       SSVAL(p,l2_attrFile,mode);
413       SIVAL(p,l2_cbList,0); /* No extended attributes */
414       SCVAL(p,l2_cchName,strlen(fname));
415       strcpy(p + l2_achName, fname);
416       nameptr = p + l2_achName;
417       p += l2_achName + strlen(fname) + 1;
418       break;
419
420     case 3:
421       SIVAL(p,0,reskey);
422       put_dos_date2(p,4,cdate);
423       put_dos_date2(p,8,adate);
424       put_dos_date2(p,12,mdate);
425       SIVAL(p,16,size);
426       SIVAL(p,20,ROUNDUP(size,1024));
427       SSVAL(p,24,mode);
428       SIVAL(p,26,4);
429       CVAL(p,30) = strlen(fname);
430       strcpy(p+31, fname);
431       nameptr = p+31;
432       p += 31 + strlen(fname) + 1;
433       break;
434
435     case 4:
436       if(requires_resume_key) {
437         SIVAL(p,0,reskey);
438         p += 4;
439       }
440       SIVAL(p,0,33+strlen(fname)+1);
441       put_dos_date2(p,4,cdate);
442       put_dos_date2(p,8,adate);
443       put_dos_date2(p,12,mdate);
444       SIVAL(p,16,size);
445       SIVAL(p,20,ROUNDUP(size,1024));
446       SSVAL(p,24,mode);
447       CVAL(p,32) = strlen(fname);
448       strcpy(p + 33, fname);
449       nameptr = p+33;
450       p += 33 + strlen(fname) + 1;
451       break;
452
453     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
454       was_8_3 = is_8_3(fname, True);
455       len = 94+strlen(fname);
456       len = (len + 3) & ~3;
457       SIVAL(p,0,len); p += 4;
458       SIVAL(p,0,reskey); p += 4;
459       put_long_date(p,cdate); p += 8;
460       put_long_date(p,adate); p += 8;
461       put_long_date(p,mdate); p += 8;
462       put_long_date(p,mdate); p += 8;
463       SIVAL(p,0,size); p += 8;
464       SIVAL(p,0,size); p += 8;
465       SIVAL(p,0,nt_extmode); p += 4;
466       SIVAL(p,0,strlen(fname)); p += 4;
467       SIVAL(p,0,0); p += 4;
468       if (!was_8_3) {
469         strcpy(p+2,fname);
470         if (!name_map_mangle(p+2,True,SNUM(cnum)))
471           (p+2)[12] = 0;
472       } else
473         *(p+2) = 0;
474       strupper(p+2);
475       SSVAL(p,0,strlen(p+2));
476       p += 2 + 24;
477       /* nameptr = p;  */
478       strcpy(p,fname); p += strlen(p);
479       p = pdata + len;
480       break;
481
482     case SMB_FIND_FILE_DIRECTORY_INFO:
483       len = 64+strlen(fname);
484       len = (len + 3) & ~3;
485       SIVAL(p,0,len); p += 4;
486       SIVAL(p,0,reskey); p += 4;
487       put_long_date(p,cdate); p += 8;
488       put_long_date(p,adate); p += 8;
489       put_long_date(p,mdate); p += 8;
490       put_long_date(p,mdate); p += 8;
491       SIVAL(p,0,size); p += 8;
492       SIVAL(p,0,size); p += 8;
493       SIVAL(p,0,nt_extmode); p += 4;
494       SIVAL(p,0,strlen(fname)); p += 4;
495       strcpy(p,fname);
496       p = pdata + len;
497       break;
498       
499       
500     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
501       len = 68+strlen(fname);
502       len = (len + 3) & ~3;
503       SIVAL(p,0,len); p += 4;
504       SIVAL(p,0,reskey); p += 4;
505       put_long_date(p,cdate); p += 8;
506       put_long_date(p,adate); p += 8;
507       put_long_date(p,mdate); p += 8;
508       put_long_date(p,mdate); p += 8;
509       SIVAL(p,0,size); p += 8;
510       SIVAL(p,0,size); p += 8;
511       SIVAL(p,0,nt_extmode); p += 4;
512       SIVAL(p,0,strlen(fname)); p += 4;
513       SIVAL(p,0,0); p += 4;
514       strcpy(p,fname);
515       p = pdata + len;
516       break;
517
518     case SMB_FIND_FILE_NAMES_INFO:
519       len = 12+strlen(fname);
520       len = (len + 3) & ~3;
521       SIVAL(p,0,len); p += 4;
522       SIVAL(p,0,reskey); p += 4;
523       SIVAL(p,0,strlen(fname)); p += 4;
524       strcpy(p,fname);
525       p = pdata + len;
526       break;
527
528     default:      
529       return(False);
530     }
531
532
533   if (PTR_DIFF(p,pdata) > space_remaining) {
534     /* Move the dirptr back to prev_dirpos */
535     SeekDir(Connections[cnum].dirptr, prev_dirpos);
536     *out_of_space = True;
537     DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
538     return False; /* Not finished - just out of space */
539   }
540
541   /* Setup the last_filename pointer, as an offset from base_data */
542   *last_name_off = PTR_DIFF(nameptr,base_data);
543   /* Advance the data pointer to the next slot */
544   *ppdata = p;
545   return(found);
546 }
547   
548 /****************************************************************************
549   reply to a TRANS2_FINDFIRST
550 ****************************************************************************/
551 static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum, 
552                          char **pparams, char **ppdata)
553 {
554   /* We must be careful here that we don't return more than the
555      allowed number of data bytes. If this means returning fewer than
556      maxentries then so be it. We assume that the redirector has
557      enough room for the fixed number of parameter bytes it has
558      requested. */
559   uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt);
560   char *params = *pparams;
561   char *pdata = *ppdata;
562   int dirtype = SVAL(params,0);
563   int maxentries = SVAL(params,2);
564   BOOL close_after_first = BITSETW(params+4,0);
565   BOOL close_if_end = BITSETW(params+4,1);
566   BOOL requires_resume_key = BITSETW(params+4,2);
567   int info_level = SVAL(params,6);
568   pstring directory;
569   pstring mask;
570   char *p, *wcard;
571   int last_name_off=0;
572   int dptr_num = -1;
573   int numentries = 0;
574   int i;
575   BOOL finished = False;
576   BOOL dont_descend = False;
577   BOOL out_of_space = False;
578   int space_remaining;
579   BOOL bad_path = False;
580
581   *directory = *mask = 0;
582
583   DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, close_if_end = %d requires_resume_key = %d level = %d, max_data_bytes = %d\n",
584            dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
585            info_level, max_data_bytes));
586   
587   switch (info_level) 
588     {
589     case 1:
590     case 2:
591     case 3:
592     case 4:
593     case SMB_FIND_FILE_DIRECTORY_INFO:
594     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
595     case SMB_FIND_FILE_NAMES_INFO:
596     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
597       break;
598     default:
599       return(ERROR(ERRDOS,ERRunknownlevel));
600     }
601
602   pstrcpy(directory, params + 12); /* Complete directory path with 
603                                      wildcard mask appended */
604
605   DEBUG(5,("path=%s\n",directory));
606
607   unix_convert(directory,cnum,0,&bad_path);
608   if(!check_name(directory,cnum)) {
609     if((errno == ENOENT) && bad_path)
610     {
611       unix_ERR_class = ERRDOS;
612       unix_ERR_code = ERRbadpath;
613     }
614
615 #if 0
616     /* Ugly - NT specific hack - maybe not needed ? (JRA) */
617     if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) && 
618        (get_remote_arch() == RA_WINNT))
619     {
620       unix_ERR_class = ERRDOS;
621       unix_ERR_code = ERRbaddirectory;
622     }
623 #endif 
624
625     return(ERROR(ERRDOS,ERRbadpath));
626   }
627
628   p = strrchr(directory,'/');
629   if(p == NULL) {
630     strcpy(mask,directory);
631     strcpy(directory,"./");
632   } else {
633     strcpy(mask,p+1);
634     *p = 0;
635   }
636
637   DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
638
639   pdata = *ppdata = Realloc(*ppdata, max_data_bytes + 1024);
640   if(!*ppdata)
641     return(ERROR(ERRDOS,ERRnomem));
642   bzero(pdata,max_data_bytes);
643
644   /* Realloc the params space */
645   params = *pparams = Realloc(*pparams, 10);
646   if(params == NULL)
647     return(ERROR(ERRDOS,ERRnomem));
648
649   dptr_num = dptr_create(cnum,directory, True ,SVAL(inbuf,smb_pid));
650   if (dptr_num < 0)
651     return(ERROR(ERRDOS,ERRbadfile));
652
653   /* convert the formatted masks */
654   {
655     p = mask;
656     while (*p) {
657       if (*p == '<') *p = '*';
658       if (*p == '>') *p = '?';
659       if (*p == '"') *p = '.';
660       p++;
661     }
662   }
663   
664   /* a special case for 16 bit apps */
665   if (strequal(mask,"????????.???")) strcpy(mask,"*");
666
667   /* handle broken clients that send us old 8.3 format */
668   string_sub(mask,"????????","*");
669   string_sub(mask,".???",".*");
670
671   /* Save the wildcard match and attribs we are using on this directory - 
672      needed as lanman2 assumes these are being saved between calls */
673
674   if(!(wcard = strdup(mask))) {
675     dptr_close(dptr_num);
676     return(ERROR(ERRDOS,ERRnomem));
677   }
678
679   dptr_set_wcard(dptr_num, wcard);
680   dptr_set_attr(dptr_num, dirtype);
681
682   DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
683
684   /* We don't need to check for VOL here as this is returned by 
685      a different TRANS2 call. */
686   
687   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
688            Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
689   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
690     dont_descend = True;
691     
692   p = pdata;
693   space_remaining = max_data_bytes;
694   out_of_space = False;
695
696   for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
697     {
698
699       /* this is a heuristic to avoid seeking the dirptr except when 
700          absolutely necessary. It allows for a filename of about 40 chars */
701       if (space_remaining < DIRLEN_GUESS && numentries > 0)
702         {
703           out_of_space = True;
704           finished = False;
705         }
706       else
707         {
708           finished = 
709             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
710                                    requires_resume_key,dont_descend,
711                                    &p,pdata,space_remaining, &out_of_space,
712                                    &last_name_off);
713         }
714
715       if (finished && out_of_space)
716         finished = False;
717
718       if (!finished && !out_of_space)
719         numentries++;
720       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
721     }
722   
723   /* Check if we can close the dirptr */
724   if(close_after_first || (finished && close_if_end))
725     {
726       dptr_close(dptr_num);
727       DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
728       dptr_num = -1;
729     }
730
731   /* 
732    * If there are no matching entries we must return ERRDOS/ERRbadfile - 
733    * from observation of NT.
734    */
735
736   if(numentries == 0)
737     return(ERROR(ERRDOS,ERRbadfile));
738
739   /* At this point pdata points to numentries directory entries. */
740
741   /* Set up the return parameter block */
742   SSVAL(params,0,dptr_num);
743   SSVAL(params,2,numentries);
744   SSVAL(params,4,finished);
745   SSVAL(params,6,0); /* Never an EA error */
746   SSVAL(params,8,last_name_off);
747
748   send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
749
750   if ((! *directory) && dptr_path(dptr_num))
751     sprintf(directory,"(%s)",dptr_path(dptr_num));
752
753   DEBUG(4,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
754         timestring(),
755         smb_fn_name(CVAL(inbuf,smb_com)), 
756         mask,directory,cnum,dirtype,numentries));
757
758   return(-1);
759 }
760
761
762 /****************************************************************************
763   reply to a TRANS2_FINDNEXT
764 ****************************************************************************/
765 static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsize,
766                         int cnum, char **pparams, char **ppdata)
767 {
768   /* We must be careful here that we don't return more than the
769      allowed number of data bytes. If this means returning fewer than
770      maxentries then so be it. We assume that the redirector has
771      enough room for the fixed number of parameter bytes it has
772      requested. */
773   int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
774   char *params = *pparams;
775   char *pdata = *ppdata;
776   int16 dptr_num = SVAL(params,0);
777   int maxentries = SVAL(params,2);
778   uint16 info_level = SVAL(params,4);
779   uint32 resume_key = IVAL(params,6);
780   BOOL close_after_request = BITSETW(params+10,0);
781   BOOL close_if_end = BITSETW(params+10,1);
782   BOOL requires_resume_key = BITSETW(params+10,2);
783   BOOL continue_bit = BITSETW(params+10,3);
784   pstring mask;
785   pstring directory;
786   char *p;
787   uint16 dirtype;
788   int numentries = 0;
789   int i, last_name_off=0;
790   BOOL finished = False;
791   BOOL dont_descend = False;
792   BOOL out_of_space = False;
793   int space_remaining;
794
795   *mask = *directory = 0;
796
797   DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, close_after_request=%d, close_if_end = %d requires_resume_key = %d resume_key = %d continue=%d level = %d\n",
798            dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, 
799            requires_resume_key, resume_key, continue_bit, info_level));
800
801   switch (info_level) 
802     {
803     case 1:
804     case 2:
805     case 3:
806     case 4:
807     case SMB_FIND_FILE_DIRECTORY_INFO:
808     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
809     case SMB_FIND_FILE_NAMES_INFO:
810     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
811       break;
812     default:
813       return(ERROR(ERRDOS,ERRunknownlevel));
814     }
815
816   pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024);
817   if(!*ppdata)
818     return(ERROR(ERRDOS,ERRnomem));
819   bzero(pdata,max_data_bytes);
820
821   /* Realloc the params space */
822   params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
823   if(!params)
824     return(ERROR(ERRDOS,ERRnomem));
825
826   /* Check that the dptr is valid */
827   if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num)))
828     return(ERROR(ERRDOS,ERRnofiles));
829
830   string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
831
832   /* Get the wildcard mask from the dptr */
833   if((p = dptr_wcard(dptr_num))== NULL) {
834     DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
835     return (ERROR(ERRDOS,ERRnofiles));
836   }
837   strcpy(mask, p);
838   strcpy(directory,Connections[cnum].dirpath);
839
840   /* Get the attr mask from the dptr */
841   dirtype = dptr_attr(dptr_num);
842
843   DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%X,%d)\n",
844            dptr_num, mask, dirtype, 
845            Connections[cnum].dirptr,
846            TellDir(Connections[cnum].dirptr)));
847
848   /* We don't need to check for VOL here as this is returned by 
849      a different TRANS2 call. */
850
851   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
852   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
853     dont_descend = True;
854     
855   p = pdata;
856   space_remaining = max_data_bytes;
857   out_of_space = False;
858
859   /* If we have a resume key - seek to the correct position. */
860   if(requires_resume_key && !continue_bit)
861     SeekDir(Connections[cnum].dirptr, resume_key);
862
863   for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
864     {
865       /* this is a heuristic to avoid seeking the dirptr except when 
866          absolutely necessary. It allows for a filename of about 40 chars */
867       if (space_remaining < DIRLEN_GUESS && numentries > 0)
868         {
869           out_of_space = True;
870           finished = False;
871         }
872       else
873         {
874           finished = 
875             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
876                                    requires_resume_key,dont_descend,
877                                    &p,pdata,space_remaining, &out_of_space,
878                                    &last_name_off);
879         }
880
881       if (finished && out_of_space)
882         finished = False;
883
884       if (!finished && !out_of_space)
885         numentries++;
886       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
887     }
888   
889   /* Check if we can close the dirptr */
890   if(close_after_request || (finished && close_if_end))
891     {
892       dptr_close(dptr_num); /* This frees up the saved mask */
893       DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
894       dptr_num = -1;
895     }
896
897
898   /* Set up the return parameter block */
899   SSVAL(params,0,numentries);
900   SSVAL(params,2,finished);
901   SSVAL(params,4,0); /* Never an EA error */
902   SSVAL(params,6,last_name_off);
903
904   send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
905
906   if ((! *directory) && dptr_path(dptr_num))
907     sprintf(directory,"(%s)",dptr_path(dptr_num));
908
909   DEBUG(3,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
910            timestring(),
911            smb_fn_name(CVAL(inbuf,smb_com)), 
912            mask,directory,cnum,dirtype,numentries));
913
914   return(-1);
915 }
916
917 /****************************************************************************
918   reply to a TRANS2_QFSINFO (query filesystem info)
919 ****************************************************************************/
920 static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
921                         int cnum, char **pparams, char **ppdata)
922 {
923   char *pdata = *ppdata;
924   char *params = *pparams;
925   uint16 info_level = SVAL(params,0);
926   int data_len;
927   struct stat st;
928   char *vname = volume_label(SNUM(cnum));
929   
930   DEBUG(3,("call_trans2qfsinfo: cnum = %d, level = %d\n", cnum, info_level));
931
932   if(sys_stat(".",&st)!=0) {
933     DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
934     return (ERROR(ERRSRV,ERRinvdevice));
935   }
936
937   pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024);
938
939   switch (info_level) 
940     {
941     case 1:
942       {
943         int dfree,dsize,bsize;
944         data_len = 18;
945         sys_disk_free(".",&bsize,&dfree,&dsize);        
946         SIVAL(pdata,l1_idFileSystem,st.st_dev);
947         SIVAL(pdata,l1_cSectorUnit,bsize/512);
948         SIVAL(pdata,l1_cUnit,dsize);
949         SIVAL(pdata,l1_cUnitAvail,dfree);
950         SSVAL(pdata,l1_cbSector,512);
951         DEBUG(5,("call_trans2qfsinfo : bsize=%d, id=%x, cSectorUnit=%d, cUnit=%d, cUnitAvail=%d, cbSector=%d\n",
952                  bsize, st.st_dev, bsize/512, dsize, dfree, 512));
953         break;
954     }
955     case 2:
956     { 
957       /* Return volume name */
958       int volname_len = MIN(strlen(vname),11);
959       data_len = l2_vol_szVolLabel + volname_len + 1;
960       put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime);
961       SCVAL(pdata,l2_vol_cch,volname_len);
962       StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
963       DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime, volname_len,
964                pdata+l2_vol_szVolLabel));
965       break;
966     }
967     case SMB_QUERY_FS_ATTRIBUTE_INFO:
968       data_len = 12 + 2*strlen(FSTYPE_STRING);
969       SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
970       SIVAL(pdata,4,128); /* Max filename component length */
971       SIVAL(pdata,8,2*strlen(FSTYPE_STRING));
972       PutUniCode(pdata+12,FSTYPE_STRING);
973       break;
974     case SMB_QUERY_FS_LABEL_INFO:
975       data_len = 4 + strlen(vname);
976       SIVAL(pdata,0,strlen(vname));
977       strcpy(pdata+4,vname);      
978       break;
979     case SMB_QUERY_FS_VOLUME_INFO:      
980       data_len = 18 + 2*strlen(vname);
981       SIVAL(pdata,12,2*strlen(vname));
982       PutUniCode(pdata+18,vname);      
983       DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", strlen(vname),
984                vname));
985       break;
986     case SMB_QUERY_FS_SIZE_INFO:
987       {
988         int dfree,dsize,bsize;
989         data_len = 24;
990         sys_disk_free(".",&bsize,&dfree,&dsize);        
991         SIVAL(pdata,0,dsize);
992         SIVAL(pdata,8,dfree);
993         SIVAL(pdata,16,bsize/512);
994         SIVAL(pdata,20,512);
995       }
996       break;
997     case SMB_QUERY_FS_DEVICE_INFO:
998       data_len = 8;
999       SIVAL(pdata,0,0); /* dev type */
1000       SIVAL(pdata,4,0); /* characteristics */
1001       break;
1002     default:
1003       return(ERROR(ERRDOS,ERRunknownlevel));
1004     }
1005
1006
1007   send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
1008
1009   DEBUG(4,("%s %s info_level =%d\n",timestring(),smb_fn_name(CVAL(inbuf,smb_com)), info_level));
1010
1011   return -1;
1012 }
1013
1014 /****************************************************************************
1015   reply to a TRANS2_SETFSINFO (set filesystem info)
1016 ****************************************************************************/
1017 static int call_trans2setfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
1018                         int cnum, char **pparams, char **ppdata)
1019 {
1020   /* Just say yes we did it - there is nothing that
1021      can be set here so it doesn't matter. */
1022   int outsize;
1023   DEBUG(3,("call_trans2setfsinfo\n"));
1024
1025   if (!CAN_WRITE(cnum))
1026     return(ERROR(ERRSRV,ERRaccess));
1027
1028   outsize = set_message(outbuf,10,0,True);
1029
1030   return outsize;
1031 }
1032
1033 /****************************************************************************
1034   reply to a TRANS2_QFILEINFO (query file info by fileid)
1035 ****************************************************************************/
1036 static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length, 
1037                                     int bufsize,int cnum,
1038                                     char **pparams,char **ppdata,
1039                                     int total_data)
1040 {
1041   char *params = *pparams;
1042   char *pdata = *ppdata;
1043   uint16 tran_call = SVAL(inbuf, smb_setup0);
1044   uint16 info_level;
1045   int mode=0;
1046   int size=0;
1047   unsigned int data_size;
1048   struct stat sbuf;
1049   pstring fname1;
1050   char *fname;
1051   char *p;
1052   int l,pos;
1053   BOOL bad_path = False;
1054
1055   if (tran_call == TRANSACT2_QFILEINFO) {
1056     int16 fnum = SVALS(params,0);
1057     info_level = SVAL(params,2);
1058
1059     CHECK_FNUM(fnum,cnum);
1060     CHECK_ERROR(fnum);
1061
1062     fname = Files[fnum].name;
1063     if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
1064       DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
1065       return(UNIXERROR(ERRDOS,ERRbadfid));
1066     }
1067     pos = lseek(Files[fnum].fd_ptr->fd,0,SEEK_CUR);
1068   } else {
1069     /* qpathinfo */
1070     info_level = SVAL(params,0);
1071     fname = &fname1[0];
1072     pstrcpy(fname,&params[6]);
1073     unix_convert(fname,cnum,0,&bad_path);
1074     if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
1075       DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
1076       if((errno == ENOENT) && bad_path)
1077       {
1078         unix_ERR_class = ERRDOS;
1079         unix_ERR_code = ERRbadpath;
1080       }
1081       return(UNIXERROR(ERRDOS,ERRbadpath));
1082     }
1083     pos = 0;
1084   }
1085
1086
1087   DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
1088            fname,info_level,tran_call,total_data));
1089
1090   p = strrchr(fname,'/'); 
1091   if (!p) 
1092     p = fname;
1093   else
1094     p++;
1095   l = strlen(p);  
1096   mode = dos_mode(cnum,fname,&sbuf);
1097   size = sbuf.st_size;
1098   if (mode & aDIR) size = 0;
1099   
1100   params = *pparams = Realloc(*pparams,2); bzero(params,2);
1101   data_size = 1024;
1102   pdata = *ppdata = Realloc(*ppdata, data_size); 
1103
1104   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1105     /* uggh, EAs for OS2 */
1106     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1107     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
1108   }
1109
1110   bzero(pdata,data_size);
1111
1112   switch (info_level) 
1113     {
1114     case SMB_INFO_STANDARD:
1115     case SMB_INFO_QUERY_EA_SIZE:
1116       data_size = (info_level==1?22:26);
1117       put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */
1118       put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */
1119       put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
1120       SIVAL(pdata,l1_cbFile,size);
1121       SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024));
1122       SSVAL(pdata,l1_attrFile,mode);
1123       SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
1124       break;
1125
1126     case SMB_INFO_QUERY_EAS_FROM_LIST:
1127       data_size = 24;
1128       put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */
1129       put_dos_date2(pdata,4,sbuf.st_atime);
1130       put_dos_date2(pdata,8,sbuf.st_mtime);
1131       SIVAL(pdata,12,size);
1132       SIVAL(pdata,16,ROUNDUP(size,1024));
1133       SIVAL(pdata,20,mode);
1134       break;
1135
1136     case SMB_INFO_QUERY_ALL_EAS:
1137       data_size = 4;
1138       SIVAL(pdata,0,data_size);
1139       break;
1140
1141     case 6:
1142       return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */      
1143
1144     case SMB_QUERY_FILE_BASIC_INFO:
1145       data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
1146       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1147       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1148       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1149       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1150       SIVAL(pdata,32,mode);
1151
1152       DEBUG(5,("SMB_QFBI - "));
1153       DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime)));
1154       DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
1155       DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
1156       DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
1157       DEBUG(5,("mode: %x\n", mode));
1158
1159       break;
1160
1161     case SMB_QUERY_FILE_STANDARD_INFO:
1162       data_size = 22;
1163       SIVAL(pdata,0,size);
1164       SIVAL(pdata,8,size);
1165       SIVAL(pdata,16,sbuf.st_nlink);
1166       CVAL(pdata,20) = 0;
1167       CVAL(pdata,21) = (mode&aDIR)?1:0;
1168       break;
1169
1170     case SMB_QUERY_FILE_EA_INFO:
1171       data_size = 4;
1172       break;
1173
1174     /* Get the 8.3 name - used if NT SMB was negotiated. */
1175     case SMB_QUERY_FILE_ALT_NAME_INFO:
1176       {
1177         pstring short_name;
1178         pstrcpy(short_name,fname);
1179         /* Mangle if not already 8.3 */
1180         if(!is_8_3(short_name, True))
1181         {
1182           if(!name_map_mangle(short_name,True,SNUM(cnum)))
1183             *short_name = '\0';
1184         }
1185         strncpy(pdata + 4,short_name,12);
1186         (pdata + 4)[12] = 0;
1187         strupper(pdata + 4);
1188         l = strlen(pdata + 4);
1189         data_size = 4 + l;
1190         SIVAL(pdata,0,l);
1191       }
1192       break;
1193
1194     case SMB_QUERY_FILE_NAME_INFO:
1195       data_size = 4 + l;
1196       SIVAL(pdata,0,l);
1197       pstrcpy(pdata+4,fname);
1198       break;
1199
1200     case SMB_QUERY_FILE_ALLOCATION_INFO:
1201     case SMB_QUERY_FILE_END_OF_FILEINFO:
1202       data_size = 8;
1203       SIVAL(pdata,0,size);
1204       break;
1205
1206     case SMB_QUERY_FILE_ALL_INFO:
1207       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1208       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1209       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1210       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1211       SIVAL(pdata,32,mode);
1212       pdata += 40;
1213       SIVAL(pdata,0,size);
1214       SIVAL(pdata,8,size);
1215       SIVAL(pdata,16,sbuf.st_nlink);
1216       CVAL(pdata,20) = 0;
1217       CVAL(pdata,21) = (mode&aDIR)?1:0;
1218       pdata += 24;
1219       pdata += 8; /* index number */
1220       pdata += 4; /* EA info */
1221       if (mode & aRONLY)
1222         SIVAL(pdata,0,0xA9);
1223       else
1224         SIVAL(pdata,0,0xd01BF);
1225       pdata += 4;
1226       SIVAL(pdata,0,pos); /* current offset */
1227       pdata += 8;
1228       SIVAL(pdata,0,mode); /* is this the right sort of mode info? */
1229       pdata += 4;
1230       pdata += 4; /* alignment */
1231       SIVAL(pdata,0,l);
1232       pstrcpy(pdata+4,fname);
1233       pdata += 4 + l;
1234       data_size = PTR_DIFF(pdata,(*ppdata));
1235       break;
1236
1237     case SMB_QUERY_FILE_STREAM_INFO:
1238       data_size = 24 + l;
1239       SIVAL(pdata,0,pos);
1240       SIVAL(pdata,4,size);
1241       SIVAL(pdata,12,size);
1242       SIVAL(pdata,20,l);        
1243       pstrcpy(pdata+24,fname);
1244       break;
1245     default:
1246       return(ERROR(ERRDOS,ERRunknownlevel));
1247     }
1248
1249   send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
1250
1251   return(-1);
1252 }
1253
1254 /****************************************************************************
1255   reply to a TRANS2_SETFILEINFO (set file info by fileid)
1256 ****************************************************************************/
1257 static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, 
1258                                       int bufsize, int cnum, char **pparams, 
1259                                       char **ppdata, int total_data)
1260 {
1261   char *params = *pparams;
1262   char *pdata = *ppdata;
1263   uint16 tran_call = SVAL(inbuf, smb_setup0);
1264   uint16 info_level;
1265   int mode=0;
1266   int size=0;
1267   struct utimbuf tvs;
1268   struct stat st;
1269   pstring fname1;
1270   char *fname;
1271   int fd = -1;
1272   BOOL bad_path = False;
1273
1274   if (!CAN_WRITE(cnum))
1275     return(ERROR(ERRSRV,ERRaccess));
1276
1277   if (tran_call == TRANSACT2_SETFILEINFO) {
1278     int16 fnum = SVALS(params,0);
1279     info_level = SVAL(params,2);    
1280
1281     CHECK_FNUM(fnum,cnum);
1282     CHECK_ERROR(fnum);
1283
1284     fname = Files[fnum].name;
1285     fd = Files[fnum].fd_ptr->fd;
1286
1287     if(fstat(fd,&st)!=0) {
1288       DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
1289       return(ERROR(ERRDOS,ERRbadpath));
1290     }
1291   } else {
1292     /* set path info */
1293     info_level = SVAL(params,0);    
1294     fname = fname1;
1295     pstrcpy(fname,&params[6]);
1296     unix_convert(fname,cnum,0,&bad_path);
1297     if(!check_name(fname, cnum))
1298     {
1299       if((errno == ENOENT) && bad_path)
1300       {
1301         unix_ERR_class = ERRDOS;
1302         unix_ERR_code = ERRbadpath;
1303       }
1304       return(UNIXERROR(ERRDOS,ERRbadpath));
1305     }
1306  
1307     if(sys_stat(fname,&st)!=0) {
1308       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
1309       if((errno == ENOENT) && bad_path)
1310       {
1311         unix_ERR_class = ERRDOS;
1312         unix_ERR_code = ERRbadpath;
1313       }
1314       return(UNIXERROR(ERRDOS,ERRbadpath));
1315     }    
1316   }
1317
1318   DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
1319            tran_call,fname,info_level,total_data));
1320
1321   /* Realloc the parameter and data sizes */
1322   params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0);
1323   if(params == NULL)
1324     return(ERROR(ERRDOS,ERRnomem));
1325
1326   size = st.st_size;
1327   tvs.modtime = st.st_mtime;
1328   tvs.actime = st.st_atime;
1329   mode = dos_mode(cnum,fname,&st);
1330
1331   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1332     /* uggh, EAs for OS2 */
1333     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1334     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
1335   }
1336
1337   switch (info_level)
1338   {
1339     case SMB_INFO_STANDARD:
1340     case SMB_INFO_QUERY_EA_SIZE:
1341     {
1342       /* access time */
1343       tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
1344
1345       /* write time */
1346       tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
1347
1348       mode = SVAL(pdata,l1_attrFile);
1349       size = IVAL(pdata,l1_cbFile);
1350       break;
1351     }
1352
1353     /* XXXX um, i don't think this is right.
1354        it's also not in the cifs6.txt spec.
1355      */
1356     case SMB_INFO_QUERY_EAS_FROM_LIST:
1357       tvs.actime = make_unix_date2(pdata+8);
1358       tvs.modtime = make_unix_date2(pdata+12);
1359       size = IVAL(pdata,16);
1360       mode = IVAL(pdata,24);
1361       break;
1362
1363     /* XXXX nor this.  not in cifs6.txt, either. */
1364     case SMB_INFO_QUERY_ALL_EAS:
1365       tvs.actime = make_unix_date2(pdata+8);
1366       tvs.modtime = make_unix_date2(pdata+12);
1367       size = IVAL(pdata,16);
1368       mode = IVAL(pdata,24);
1369       break;
1370
1371     case SMB_SET_FILE_BASIC_INFO:
1372     {
1373       /* Ignore create time at offset pdata. */
1374
1375       /* access time */
1376       tvs.actime = interpret_long_date(pdata+8);
1377
1378       /* write time + changed time, combined. */
1379       tvs.modtime=MAX(interpret_long_date(pdata+16),
1380                       interpret_long_date(pdata+24));
1381
1382 #if 0 /* Needs more testing... */
1383       /* Test from Luke to prevent Win95 from
1384          setting incorrect values here.
1385        */
1386       if (tvs.actime < tvs.modtime)
1387         return(ERROR(ERRDOS,ERRnoaccess));
1388 #endif /* Needs more testing... */
1389
1390       /* attributes */
1391       mode = IVAL(pdata,32);
1392       break;
1393     }
1394
1395     case SMB_SET_FILE_END_OF_FILE_INFO:
1396     {
1397       if (IVAL(pdata,4) != 0)   /* more than 32 bits? */
1398          return(ERROR(ERRDOS,ERRunknownlevel));
1399       size = IVAL(pdata,0);
1400       break;
1401     }
1402
1403     case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
1404     case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
1405     default:
1406     {
1407       return(ERROR(ERRDOS,ERRunknownlevel));
1408     }
1409   }
1410
1411   DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
1412   DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
1413   DEBUG(6,("size: %x "   , size));
1414   DEBUG(6,("mode: %x\n"  , mode));
1415
1416   /* get some defaults (no modifications) if any info is zero. */
1417   if (!tvs.actime) tvs.actime = st.st_atime;
1418   if (!tvs.modtime) tvs.modtime = st.st_mtime;
1419   if (!size) size = st.st_size;
1420
1421   /* Try and set the times, size and mode of this file -
1422      if they are different from the current values
1423    */
1424   if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
1425   {
1426     if(file_utime(cnum, fname, &tvs)!=0)
1427     {
1428       return(ERROR(ERRDOS,ERRnoaccess));
1429     }
1430   }
1431
1432   /* check the mode isn't different, before changing it */
1433   if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
1434   {
1435     DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
1436     return(ERROR(ERRDOS,ERRnoaccess));
1437   }
1438
1439   if(size != st.st_size)
1440   {
1441     if (fd == -1)
1442     {
1443       fd = sys_open(fname,O_RDWR,0);
1444       if (fd == -1)
1445       {
1446         return(ERROR(ERRDOS,ERRbadpath));
1447       }
1448       set_filelen(fd, size);
1449       close(fd);
1450     }
1451     else
1452     {
1453       set_filelen(fd, size);
1454     }
1455   }
1456
1457   SSVAL(params,0,0);
1458
1459   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1460   
1461   return(-1);
1462 }
1463
1464 /****************************************************************************
1465   reply to a TRANS2_MKDIR (make directory with extended attributes).
1466 ****************************************************************************/
1467 static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
1468                         int cnum, char **pparams, char **ppdata)
1469 {
1470   char *params = *pparams;
1471   pstring directory;
1472   int ret = -1;
1473   BOOL bad_path = False;
1474
1475   if (!CAN_WRITE(cnum))
1476     return(ERROR(ERRSRV,ERRaccess));
1477
1478   pstrcpy(directory, &params[4]);
1479
1480   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
1481
1482   unix_convert(directory,cnum,0,&bad_path);
1483   if (check_name(directory,cnum))
1484     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
1485   
1486   if(ret < 0)
1487     {
1488       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
1489       if((errno == ENOENT) && bad_path)
1490       {
1491         unix_ERR_class = ERRDOS;
1492         unix_ERR_code = ERRbadpath;
1493       }
1494       return(UNIXERROR(ERRDOS,ERRnoaccess));
1495     }
1496
1497   /* Realloc the parameter and data sizes */
1498   params = *pparams = Realloc(*pparams,2);
1499   if(params == NULL)
1500     return(ERROR(ERRDOS,ERRnomem));
1501
1502   SSVAL(params,0,0);
1503
1504   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1505   
1506   return(-1);
1507 }
1508
1509 /****************************************************************************
1510   reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes)
1511   We don't actually do this - we just send a null response.
1512 ****************************************************************************/
1513 static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int bufsize,
1514                         int cnum, char **pparams, char **ppdata)
1515 {
1516   static uint16 fnf_handle = 257;
1517   char *params = *pparams;
1518   uint16 info_level = SVAL(params,4);
1519
1520   DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
1521
1522   switch (info_level) 
1523     {
1524     case 1:
1525     case 2:
1526       break;
1527     default:
1528       return(ERROR(ERRDOS,ERRunknownlevel));
1529     }
1530
1531   /* Realloc the parameter and data sizes */
1532   params = *pparams = Realloc(*pparams,6);
1533   if(params == NULL)
1534     return(ERROR(ERRDOS,ERRnomem));
1535
1536   SSVAL(params,0,fnf_handle);
1537   SSVAL(params,2,0); /* No changes */
1538   SSVAL(params,4,0); /* No EA errors */
1539
1540   fnf_handle++;
1541
1542   if(fnf_handle == 0)
1543     fnf_handle = 257;
1544
1545   send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
1546   
1547   return(-1);
1548 }
1549
1550 /****************************************************************************
1551   reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for 
1552   changes). Currently this does nothing.
1553 ****************************************************************************/
1554 static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int bufsize,
1555                         int cnum, char **pparams, char **ppdata)
1556 {
1557   char *params = *pparams;
1558
1559   DEBUG(3,("call_trans2findnotifynext\n"));
1560
1561   /* Realloc the parameter and data sizes */
1562   params = *pparams = Realloc(*pparams,4);
1563   if(params == NULL)
1564     return(ERROR(ERRDOS,ERRnomem));
1565
1566   SSVAL(params,0,0); /* No changes */
1567   SSVAL(params,2,0); /* No EA errors */
1568
1569   send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
1570   
1571   return(-1);
1572 }
1573
1574 /****************************************************************************
1575   reply to a SMBfindclose (stop trans2 directory search)
1576 ****************************************************************************/
1577 int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
1578 {
1579   int cnum;
1580   int outsize = 0;
1581   int16 dptr_num=SVALS(inbuf,smb_vwv0);
1582
1583   cnum = SVAL(inbuf,smb_tid);
1584
1585   DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1586
1587   dptr_close(dptr_num);
1588
1589   outsize = set_message(outbuf,0,0,True);
1590
1591   DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1592
1593   return(outsize);
1594 }
1595
1596 /****************************************************************************
1597   reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
1598 ****************************************************************************/
1599 int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
1600 {
1601   int cnum;
1602   int outsize = 0;
1603   int dptr_num= -1;
1604
1605   cnum = SVAL(inbuf,smb_tid);
1606   dptr_num = SVAL(inbuf,smb_vwv0);
1607
1608   DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1609
1610   /* We never give out valid handles for a 
1611      findnotifyfirst - so any dptr_num is ok here. 
1612      Just ignore it. */
1613
1614   outsize = set_message(outbuf,0,0,True);
1615
1616   DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1617
1618   return(outsize);
1619 }
1620
1621
1622 /****************************************************************************
1623   reply to a SMBtranss2 - just ignore it!
1624 ****************************************************************************/
1625 int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize)
1626 {
1627   DEBUG(4,("Ignoring transs2 of length %d\n",length));
1628   return(-1);
1629 }
1630
1631 /****************************************************************************
1632   reply to a SMBtrans2
1633 ****************************************************************************/
1634 int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
1635 {
1636   int outsize = 0;
1637   int cnum = SVAL(inbuf,smb_tid);
1638   unsigned int total_params = SVAL(inbuf, smb_tpscnt);
1639   unsigned int total_data =SVAL(inbuf, smb_tdscnt);
1640 #if 0
1641   unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
1642   unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
1643   unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
1644   BOOL close_tid = BITSETW(inbuf+smb_flags,0);
1645   BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
1646   int32 timeout = IVALS(inbuf,smb_timeout);
1647 #endif
1648   unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
1649   unsigned int tran_call = SVAL(inbuf, smb_setup0);
1650   char *params = NULL, *data = NULL;
1651   int num_params, num_params_sofar, num_data, num_data_sofar;
1652
1653   outsize = set_message(outbuf,0,0,True);
1654
1655   /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
1656      is so as a sanity check */
1657   if(suwcnt != 1 )
1658     {
1659       DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
1660       return(ERROR(ERRSRV,ERRerror));
1661     }
1662     
1663   /* Allocate the space for the maximum needed parameters and data */
1664   if (total_params > 0)
1665     params = (char *)malloc(total_params);
1666   if (total_data > 0)
1667     data = (char *)malloc(total_data);
1668   
1669   if ((total_params && !params)  || (total_data && !data))
1670     {
1671       DEBUG(2,("Out of memory in reply_trans2\n"));
1672       return(ERROR(ERRDOS,ERRnomem));
1673     }
1674
1675   /* Copy the param and data bytes sent with this request into
1676      the params buffer */
1677   num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
1678   num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
1679
1680   if (num_params > total_params || num_data > total_data)
1681           exit_server("invalid params in reply_trans2");
1682
1683   memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
1684   memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
1685
1686   if(num_data_sofar < total_data || num_params_sofar < total_params)
1687     {
1688     /* We need to send an interim response then receive the rest
1689        of the parameter/data bytes */
1690       outsize = set_message(outbuf,0,0,True);
1691       send_smb(Client,outbuf);
1692
1693       while( num_data_sofar < total_data || num_params_sofar < total_params)
1694         {
1695           BOOL ret;
1696
1697           ret = receive_next_smb(Client,oplock_sock,inbuf,bufsize,
1698                              SMB_SECONDARY_WAIT);
1699
1700           if((ret && (CVAL(inbuf, smb_com) != SMBtranss2)) || !ret)
1701             {
1702               outsize = set_message(outbuf,0,0,True);
1703               if(ret)
1704                 DEBUG(0,("reply_trans2: Invalid secondary trans2 packet\n"));
1705               else
1706                 DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
1707                          (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
1708               free(params);
1709               free(data);
1710               return(ERROR(ERRSRV,ERRerror));
1711             }
1712       
1713           /* Revise total_params and total_data in case they have changed downwards */
1714           total_params = SVAL(inbuf, smb_tpscnt);
1715           total_data = SVAL(inbuf, smb_tdscnt);
1716           num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
1717           num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
1718           if (num_params_sofar > total_params || num_data_sofar > total_data)
1719                   exit_server("data overflow in trans2");
1720
1721           memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
1722                  smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
1723           memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
1724                  smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
1725         }
1726     }
1727
1728   if (Protocol >= PROTOCOL_NT1) {
1729     uint16 flg2 = SVAL(outbuf,smb_flg2);
1730     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1731   }
1732
1733   /* Now we must call the relevant TRANS2 function */
1734   switch(tran_call) 
1735     {
1736     case TRANSACT2_OPEN:
1737       outsize = call_trans2open(inbuf, outbuf, bufsize, cnum, &params, &data);
1738       break;
1739     case TRANSACT2_FINDFIRST:
1740       outsize = call_trans2findfirst(inbuf, outbuf, bufsize, cnum, &params, &data);
1741       break;
1742     case TRANSACT2_FINDNEXT:
1743       outsize = call_trans2findnext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1744       break;
1745     case TRANSACT2_QFSINFO:
1746       outsize = call_trans2qfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1747       break;
1748     case TRANSACT2_SETFSINFO:
1749       outsize = call_trans2setfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1750       break;
1751     case TRANSACT2_QPATHINFO:
1752     case TRANSACT2_QFILEINFO:
1753       outsize = call_trans2qfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1754       break;
1755     case TRANSACT2_SETPATHINFO:
1756     case TRANSACT2_SETFILEINFO:
1757       outsize = call_trans2setfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1758       break;
1759     case TRANSACT2_FINDNOTIFYFIRST:
1760       outsize = call_trans2findnotifyfirst(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1761       break;
1762     case TRANSACT2_FINDNOTIFYNEXT:
1763       outsize = call_trans2findnotifynext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1764       break;
1765     case TRANSACT2_MKDIR:
1766       outsize = call_trans2mkdir(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1767       break;
1768     default:
1769       /* Error in request */
1770       DEBUG(2,("%s Unknown request %d in trans2 call\n",timestring(), tran_call));
1771       if(params)
1772         free(params);
1773       if(data)
1774         free(data);
1775       return (ERROR(ERRSRV,ERRerror));
1776     }
1777
1778   /* As we do not know how many data packets will need to be
1779      returned here the various call_trans2xxxx calls
1780      must send their own. Thus a call_trans2xxx routine only
1781      returns a value other than -1 when it wants to send
1782      an error packet. 
1783   */
1784
1785   if(params)
1786     free(params);
1787   if(data)
1788     free(data);
1789   return outsize; /* If a correct response was needed the call_trans2xxx 
1790                      calls have already sent it. If outsize != -1 then it is
1791                      returning an error packet. */
1792 }