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