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