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