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