e7fd6824abd2162a302f335a90cc128a68b7700e
[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     {
618       if(dptr_num == -2)
619         return (UNIXERROR(ERRDOS,ERRbadpath));
620       return(ERROR(ERRDOS,ERRbadpath));
621     }
622
623   /* convert the formatted masks */
624   {
625     p = mask;
626     while (*p) {
627       if (*p == '<') *p = '*';
628       if (*p == '>') *p = '?';
629       if (*p == '"') *p = '.';
630       p++;
631     }
632   }
633   
634   /* a special case for 16 bit apps */
635   if (strequal(mask,"????????.???")) strcpy(mask,"*");
636
637   /* handle broken clients that send us old 8.3 format */
638   string_sub(mask,"????????","*");
639   string_sub(mask,".???",".*");
640
641   /* Save the wildcard match and attribs we are using on this directory - 
642      needed as lanman2 assumes these are being saved between calls */
643
644   if(!(wcard = strdup(mask))) {
645     dptr_close(dptr_num);
646     return(ERROR(ERRDOS,ERRnomem));
647   }
648
649   dptr_set_wcard(dptr_num, wcard);
650   dptr_set_attr(dptr_num, dirtype);
651
652   DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
653
654   /* We don't need to check for VOL here as this is returned by 
655      a different TRANS2 call. */
656   
657   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
658            Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
659   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
660     dont_descend = True;
661     
662   p = pdata;
663   space_remaining = max_data_bytes;
664   out_of_space = False;
665
666   for (i=0;(i<maxentries) && !finished && !out_of_space;i++)
667     {
668
669       /* this is a heuristic to avoid seeking the dirptr except when 
670          absolutely necessary. It allows for a filename of about 40 chars */
671       if (space_remaining < DIRLEN_GUESS && numentries > 0)
672         {
673           out_of_space = True;
674           finished = False;
675         }
676       else
677         {
678           finished = 
679             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
680                                    requires_resume_key,dont_descend,
681                                    &p,pdata,space_remaining, &out_of_space,
682                                    &last_name_off);
683         }
684
685       if (finished && out_of_space)
686         finished = False;
687
688       if (!finished && !out_of_space)
689         numentries++;
690       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
691     }
692   
693   /* Check if we can close the dirptr */
694   if(close_after_first || (finished && close_if_end))
695     {
696       dptr_close(dptr_num);
697       DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
698       dptr_num = -1;
699     }
700
701   /* At this point pdata points to numentries directory entries. */
702
703   /* Set up the return parameter block */
704   SSVAL(params,0,dptr_num);
705   SSVAL(params,2,numentries);
706   SSVAL(params,4,finished);
707   SSVAL(params,6,0); /* Never an EA error */
708   SSVAL(params,8,last_name_off);
709
710   send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
711
712   if ((! *directory) && dptr_path(dptr_num))
713     sprintf(directory,"(%s)",dptr_path(dptr_num));
714
715   DEBUG(4,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
716         timestring(),
717         smb_fn_name(CVAL(inbuf,smb_com)), 
718         mask,directory,cnum,dirtype,numentries));
719
720   return(-1);
721 }
722
723
724 /****************************************************************************
725   reply to a TRANS2_FINDNEXT
726 ****************************************************************************/
727 static int call_trans2findnext(char *inbuf, char *outbuf, int length, int bufsize,
728                         int cnum, char **pparams, char **ppdata)
729 {
730   /* We must be careful here that we don't return more than the
731      allowed number of data bytes. If this means returning fewer than
732      maxentries then so be it. We assume that the redirector has
733      enough room for the fixed number of parameter bytes it has
734      requested. */
735   int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
736   char *params = *pparams;
737   char *pdata = *ppdata;
738   int16 dptr_num = SVAL(params,0);
739   int maxentries = SVAL(params,2);
740   uint16 info_level = SVAL(params,4);
741   uint32 resume_key = IVAL(params,6);
742   BOOL close_after_request = BITSETW(params+10,0);
743   BOOL close_if_end = BITSETW(params+10,1);
744   BOOL requires_resume_key = BITSETW(params+10,2);
745   BOOL continue_bit = BITSETW(params+10,3);
746   pstring mask;
747   pstring directory;
748   char *p;
749   uint16 dirtype;
750   int numentries = 0;
751   int i, last_name_off=0;
752   BOOL finished = False;
753   BOOL dont_descend = False;
754   BOOL out_of_space = False;
755   int space_remaining;
756
757   *mask = *directory = 0;
758
759   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",
760            dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, 
761            requires_resume_key, resume_key, continue_bit, info_level));
762
763   switch (info_level) 
764     {
765     case 1:
766     case 2:
767     case 3:
768     case 4:
769     case SMB_FIND_FILE_DIRECTORY_INFO:
770     case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
771     case SMB_FIND_FILE_NAMES_INFO:
772     case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
773       break;
774     default:
775       return(ERROR(ERRDOS,ERRunknownlevel));
776     }
777
778   pdata = *ppdata = Realloc( *ppdata, max_data_bytes + 1024);
779   if(!*ppdata)
780     return(ERROR(ERRDOS,ERRnomem));
781   bzero(pdata,max_data_bytes);
782
783   /* Realloc the params space */
784   params = *pparams = Realloc(*pparams, 6*SIZEOFWORD);
785   if(!params)
786     return(ERROR(ERRDOS,ERRnomem));
787
788   /* Check that the dptr is valid */
789   if(!(Connections[cnum].dirptr = dptr_fetch_lanman2(params, dptr_num)))
790     return(ERROR(ERRDOS,ERRnofiles));
791
792   string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
793
794   /* Get the wildcard mask from the dptr */
795   if((p = dptr_wcard(dptr_num))== NULL) {
796     DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
797     return (ERROR(ERRDOS,ERRnofiles));
798   }
799   strcpy(mask, p);
800   strcpy(directory,Connections[cnum].dirpath);
801
802   /* Get the attr mask from the dptr */
803   dirtype = dptr_attr(dptr_num);
804
805   DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%X,%d)\n",
806            dptr_num, mask, dirtype, 
807            Connections[cnum].dirptr,
808            TellDir(Connections[cnum].dirptr)));
809
810   /* We don't need to check for VOL here as this is returned by 
811      a different TRANS2 call. */
812
813   DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
814   if (in_list(Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum)),case_sensitive))
815     dont_descend = True;
816     
817   p = pdata;
818   space_remaining = max_data_bytes;
819   out_of_space = False;
820
821   /* If we have a resume key - seek to the correct position. */
822   if(requires_resume_key && !continue_bit)
823     SeekDir(Connections[cnum].dirptr, resume_key);
824
825   for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++)
826     {
827       /* this is a heuristic to avoid seeking the dirptr except when 
828          absolutely necessary. It allows for a filename of about 40 chars */
829       if (space_remaining < DIRLEN_GUESS && numentries > 0)
830         {
831           out_of_space = True;
832           finished = False;
833         }
834       else
835         {
836           finished = 
837             !get_lanman2_dir_entry(cnum,mask,dirtype,info_level,
838                                    requires_resume_key,dont_descend,
839                                    &p,pdata,space_remaining, &out_of_space,
840                                    &last_name_off);
841         }
842
843       if (finished && out_of_space)
844         finished = False;
845
846       if (!finished && !out_of_space)
847         numentries++;
848       space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
849     }
850   
851   /* Check if we can close the dirptr */
852   if(close_after_request || (finished && close_if_end))
853     {
854       dptr_close(dptr_num); /* This frees up the saved mask */
855       DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
856       dptr_num = -1;
857     }
858
859
860   /* Set up the return parameter block */
861   SSVAL(params,0,numentries);
862   SSVAL(params,2,finished);
863   SSVAL(params,4,0); /* Never an EA error */
864   SSVAL(params,6,last_name_off);
865
866   send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
867
868   if ((! *directory) && dptr_path(dptr_num))
869     sprintf(directory,"(%s)",dptr_path(dptr_num));
870
871   DEBUG(3,("%s %s mask=%s directory=%s cnum=%d dirtype=%d numentries=%d\n",
872            timestring(),
873            smb_fn_name(CVAL(inbuf,smb_com)), 
874            mask,directory,cnum,dirtype,numentries));
875
876   return(-1);
877 }
878
879 /****************************************************************************
880   reply to a TRANS2_QFSINFO (query filesystem info)
881 ****************************************************************************/
882 static int call_trans2qfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
883                         int cnum, char **pparams, char **ppdata)
884 {
885   char *pdata = *ppdata;
886   char *params = *pparams;
887   uint16 info_level = SVAL(params,0);
888   int data_len;
889   struct stat st;
890   char *vname = volume_label(SNUM(cnum));
891   
892   DEBUG(3,("call_trans2qfsinfo: cnum = %d, level = %d\n", cnum, info_level));
893
894   if(sys_stat(".",&st)!=0) {
895     DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
896     return (ERROR(ERRSRV,ERRinvdevice));
897   }
898
899   pdata = *ppdata = Realloc(*ppdata, 1024); bzero(pdata,1024);
900
901   switch (info_level) 
902     {
903     case 1:
904       {
905         int dfree,dsize,bsize;
906         data_len = 18;
907         sys_disk_free(".",&bsize,&dfree,&dsize);        
908         SIVAL(pdata,l1_idFileSystem,st.st_dev);
909         SIVAL(pdata,l1_cSectorUnit,bsize/512);
910         SIVAL(pdata,l1_cUnit,dsize);
911         SIVAL(pdata,l1_cUnitAvail,dfree);
912         SSVAL(pdata,l1_cbSector,512);
913         DEBUG(5,("call_trans2qfsinfo : bsize=%d, id=%x, cSectorUnit=%d, cUnit=%d, cUnitAvail=%d, cbSector=%d\n",
914                  bsize, st.st_dev, bsize/512, dsize, dfree, 512));
915         break;
916     }
917     case 2:
918     { 
919       /* Return volume name */
920       int volname_len = MIN(strlen(vname),11);
921       data_len = l2_vol_szVolLabel + volname_len + 1;
922       put_dos_date2(pdata,l2_vol_fdateCreation,st.st_ctime);
923       SCVAL(pdata,l2_vol_cch,volname_len);
924       StrnCpy(pdata+l2_vol_szVolLabel,vname,volname_len);
925       DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",st.st_ctime, volname_len,
926                pdata+l2_vol_szVolLabel));
927       break;
928     }
929     case SMB_QUERY_FS_ATTRIBUTE_INFO:
930       data_len = 12 + 2*strlen(FSTYPE_STRING);
931       SIVAL(pdata,0,0x4006); /* FS ATTRIBUTES == long filenames supported? */
932       SIVAL(pdata,4,128); /* Max filename component length */
933       SIVAL(pdata,8,2*strlen(FSTYPE_STRING));
934       PutUniCode(pdata+12,FSTYPE_STRING);
935       break;
936     case SMB_QUERY_FS_LABEL_INFO:
937       data_len = 4 + strlen(vname);
938       SIVAL(pdata,0,strlen(vname));
939       strcpy(pdata+4,vname);      
940       break;
941     case SMB_QUERY_FS_VOLUME_INFO:      
942       data_len = 18 + 2*strlen(vname);
943       SIVAL(pdata,12,2*strlen(vname));
944       PutUniCode(pdata+18,vname);      
945       DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol = %s\n", strlen(vname),
946                vname));
947       break;
948     case SMB_QUERY_FS_SIZE_INFO:
949       {
950         int dfree,dsize,bsize;
951         data_len = 24;
952         sys_disk_free(".",&bsize,&dfree,&dsize);        
953         SIVAL(pdata,0,dsize);
954         SIVAL(pdata,8,dfree);
955         SIVAL(pdata,16,bsize/512);
956         SIVAL(pdata,20,512);
957       }
958       break;
959     case SMB_QUERY_FS_DEVICE_INFO:
960       data_len = 8;
961       SIVAL(pdata,0,0); /* dev type */
962       SIVAL(pdata,4,0); /* characteristics */
963       break;
964     default:
965       return(ERROR(ERRDOS,ERRunknownlevel));
966     }
967
968
969   send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len);
970
971   DEBUG(4,("%s %s info_level =%d\n",timestring(),smb_fn_name(CVAL(inbuf,smb_com)), info_level));
972
973   return -1;
974 }
975
976 /****************************************************************************
977   reply to a TRANS2_SETFSINFO (set filesystem info)
978 ****************************************************************************/
979 static int call_trans2setfsinfo(char *inbuf, char *outbuf, int length, int bufsize,
980                         int cnum, char **pparams, char **ppdata)
981 {
982   /* Just say yes we did it - there is nothing that
983      can be set here so it doesn't matter. */
984   int outsize;
985   DEBUG(3,("call_trans2setfsinfo\n"));
986
987   if (!CAN_WRITE(cnum))
988     return(ERROR(ERRSRV,ERRaccess));
989
990   outsize = set_message(outbuf,10,0,True);
991
992   return outsize;
993 }
994
995 /****************************************************************************
996   reply to a TRANS2_QFILEINFO (query file info by fileid)
997 ****************************************************************************/
998 static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length, 
999                                     int bufsize,int cnum,
1000                                     char **pparams,char **ppdata,
1001                                     int total_data)
1002 {
1003   char *params = *pparams;
1004   char *pdata = *ppdata;
1005   uint16 tran_call = SVAL(inbuf, smb_setup0);
1006   uint16 info_level;
1007   int mode=0;
1008   int size=0;
1009   unsigned int data_size;
1010   struct stat sbuf;
1011   pstring fname1;
1012   char *fname;
1013   char *p;
1014   int l,pos;
1015
1016
1017   if (tran_call == TRANSACT2_QFILEINFO) {
1018     int16 fnum = SVALS(params,0);
1019     info_level = SVAL(params,2);
1020
1021     CHECK_FNUM(fnum,cnum);
1022     CHECK_ERROR(fnum);
1023
1024     fname = Files[fnum].name;
1025     if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
1026       DEBUG(3,("fstat of fnum %d failed (%s)\n",fnum, strerror(errno)));
1027       return(UNIXERROR(ERRDOS,ERRbadfid));
1028     }
1029     pos = lseek(Files[fnum].fd_ptr->fd,0,SEEK_CUR);
1030   } else {
1031     /* qpathinfo */
1032     info_level = SVAL(params,0);
1033     fname = &fname1[0];
1034     strcpy(fname,&params[6]);
1035     unix_convert(fname,cnum,0);
1036     if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
1037       DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
1038       return(UNIXERROR(ERRDOS,ERRbadpath));
1039     }
1040     pos = 0;
1041   }
1042
1043
1044   DEBUG(3,("call_trans2qfilepathinfo %s level=%d call=%d total_data=%d\n",
1045            fname,info_level,tran_call,total_data));
1046
1047   p = strrchr(fname,'/'); 
1048   if (!p) 
1049     p = fname;
1050   else
1051     p++;
1052   l = strlen(p);  
1053   mode = dos_mode(cnum,fname,&sbuf);
1054   size = sbuf.st_size;
1055   if (mode & aDIR) size = 0;
1056   
1057   params = *pparams = Realloc(*pparams,2); bzero(params,2);
1058   data_size = 1024;
1059   pdata = *ppdata = Realloc(*ppdata, data_size); 
1060
1061   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1062     /* uggh, EAs for OS2 */
1063     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1064 #if 0
1065     SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
1066     send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1067     return(-1);
1068 #else
1069     return(ERROR(ERRDOS,ERROR_EAS_NOT_SUPPORTED));
1070 #endif
1071   }
1072
1073   bzero(pdata,data_size);
1074
1075   switch (info_level) 
1076     {
1077     case SMB_INFO_STANDARD:
1078     case SMB_INFO_QUERY_EA_SIZE:
1079       data_size = (info_level==1?22:26);
1080       put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */
1081       put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */
1082       put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
1083       SIVAL(pdata,l1_cbFile,size);
1084       SIVAL(pdata,l1_cbFileAlloc,ROUNDUP(size,1024));
1085       SSVAL(pdata,l1_attrFile,mode);
1086       SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
1087       break;
1088
1089     case SMB_INFO_QUERY_EAS_FROM_LIST:
1090       data_size = 24;
1091       put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */
1092       put_dos_date2(pdata,4,sbuf.st_atime);
1093       put_dos_date2(pdata,8,sbuf.st_mtime);
1094       SIVAL(pdata,12,size);
1095       SIVAL(pdata,16,ROUNDUP(size,1024));
1096       SIVAL(pdata,20,mode);
1097       break;
1098
1099     case SMB_INFO_QUERY_ALL_EAS:
1100       data_size = 4;
1101       SIVAL(pdata,0,data_size);
1102       break;
1103
1104     case 6:
1105       return(ERROR(ERRDOS,ERRbadfunc)); /* os/2 needs this */      
1106
1107     case SMB_QUERY_FILE_BASIC_INFO:
1108       data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
1109       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1110       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1111       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1112       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1113       SIVAL(pdata,32,mode);
1114
1115       DEBUG(5,("SMB_QFBI - "));
1116       DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime)));
1117       DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
1118       DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
1119       DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
1120       DEBUG(5,("mode: %x\n", mode));
1121
1122       break;
1123
1124     case SMB_QUERY_FILE_STANDARD_INFO:
1125       data_size = 22;
1126       SIVAL(pdata,0,size);
1127       SIVAL(pdata,8,size);
1128       SIVAL(pdata,16,sbuf.st_nlink);
1129       CVAL(pdata,20) = 0;
1130       CVAL(pdata,21) = (mode&aDIR)?1:0;
1131       break;
1132
1133     case SMB_QUERY_FILE_EA_INFO:
1134       data_size = 4;
1135       break;
1136
1137     case SMB_QUERY_FILE_NAME_INFO:
1138     case SMB_QUERY_FILE_ALT_NAME_INFO:
1139       data_size = 4 + l;
1140       SIVAL(pdata,0,l);
1141       strcpy(pdata+4,fname);
1142       break;
1143     case SMB_QUERY_FILE_ALLOCATION_INFO:
1144     case SMB_QUERY_FILE_END_OF_FILEINFO:
1145       data_size = 8;
1146       SIVAL(pdata,0,size);
1147       break;
1148
1149     case SMB_QUERY_FILE_ALL_INFO:
1150       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1151       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1152       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1153       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1154       SIVAL(pdata,32,mode);
1155       pdata += 40;
1156       SIVAL(pdata,0,size);
1157       SIVAL(pdata,8,size);
1158       SIVAL(pdata,16,sbuf.st_nlink);
1159       CVAL(pdata,20) = 0;
1160       CVAL(pdata,21) = (mode&aDIR)?1:0;
1161       pdata += 24;
1162       pdata += 8; /* index number */
1163       pdata += 4; /* EA info */
1164       if (mode & aRONLY)
1165         SIVAL(pdata,0,0xA9);
1166       else
1167         SIVAL(pdata,0,0xd01BF);
1168       pdata += 4;
1169       SIVAL(pdata,0,pos); /* current offset */
1170       pdata += 8;
1171       SIVAL(pdata,0,mode); /* is this the right sort of mode info? */
1172       pdata += 4;
1173       pdata += 4; /* alignment */
1174       SIVAL(pdata,0,l);
1175       strcpy(pdata+4,fname);
1176       pdata += 4 + l;
1177       data_size = PTR_DIFF(pdata,(*ppdata));
1178       break;
1179
1180     case SMB_QUERY_FILE_STREAM_INFO:
1181       data_size = 24 + l;
1182       SIVAL(pdata,0,pos);
1183       SIVAL(pdata,4,size);
1184       SIVAL(pdata,12,size);
1185       SIVAL(pdata,20,l);        
1186       strcpy(pdata+24,fname);
1187       break;
1188     default:
1189       return(ERROR(ERRDOS,ERRunknownlevel));
1190     }
1191
1192   send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
1193
1194   return(-1);
1195 }
1196
1197 /****************************************************************************
1198   reply to a TRANS2_SETFILEINFO (set file info by fileid)
1199 ****************************************************************************/
1200 static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, 
1201                                       int bufsize, int cnum, char **pparams, 
1202                                       char **ppdata, int total_data)
1203 {
1204   char *params = *pparams;
1205   char *pdata = *ppdata;
1206   uint16 tran_call = SVAL(inbuf, smb_setup0);
1207   uint16 info_level;
1208   int mode=0;
1209   int size=0;
1210   struct utimbuf tvs;
1211   struct stat st;
1212   pstring fname1;
1213   char *fname;
1214   int fd = -1;
1215
1216   if (!CAN_WRITE(cnum))
1217     return(ERROR(ERRSRV,ERRaccess));
1218
1219   if (tran_call == TRANSACT2_SETFILEINFO) {
1220     int16 fnum = SVALS(params,0);
1221     info_level = SVAL(params,2);    
1222
1223     CHECK_FNUM(fnum,cnum);
1224     CHECK_ERROR(fnum);
1225
1226     fname = Files[fnum].name;
1227     fd = Files[fnum].fd_ptr->fd;
1228
1229     if(fstat(fd,&st)!=0) {
1230       DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
1231       return(ERROR(ERRDOS,ERRbadpath));
1232     }
1233   } else {
1234     /* set path info */
1235     info_level = SVAL(params,0);    
1236     fname = fname1;
1237     strcpy(fname,&params[6]);
1238     unix_convert(fname,cnum,0);
1239     if(!check_name(fname, cnum))
1240       return(ERROR(ERRDOS,ERRbadpath));
1241     
1242     if(sys_stat(fname,&st)!=0) {
1243       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
1244       return(ERROR(ERRDOS,ERRbadpath));
1245     }    
1246   }
1247
1248   DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
1249            tran_call,fname,info_level,total_data));
1250
1251   /* Realloc the parameter and data sizes */
1252   params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0);
1253   if(params == NULL)
1254     return(ERROR(ERRDOS,ERRnomem));
1255
1256   size = st.st_size;
1257   tvs.modtime = st.st_mtime;
1258   tvs.actime = st.st_atime;
1259   mode = dos_mode(cnum,fname,&st);
1260
1261   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1262     /* uggh, EAs for OS2 */
1263     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1264     SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
1265
1266     send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1267   
1268     return(-1);    
1269   }
1270
1271   switch (info_level)
1272   {
1273     case SMB_INFO_STANDARD:
1274     case SMB_INFO_QUERY_EA_SIZE:
1275     {
1276       /* access time */
1277       tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
1278
1279       /* write time */
1280       tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
1281
1282       mode = SVAL(pdata,l1_attrFile);
1283       size = IVAL(pdata,l1_cbFile);
1284       break;
1285     }
1286
1287     /* XXXX um, i don't think this is right.
1288        it's also not in the cifs6.txt spec.
1289      */
1290     case SMB_INFO_QUERY_EAS_FROM_LIST:
1291       tvs.actime = make_unix_date2(pdata+8);
1292       tvs.modtime = make_unix_date2(pdata+12);
1293       size = IVAL(pdata,16);
1294       mode = IVAL(pdata,24);
1295       break;
1296
1297     /* XXXX nor this.  not in cifs6.txt, either. */
1298     case SMB_INFO_QUERY_ALL_EAS:
1299       tvs.actime = make_unix_date2(pdata+8);
1300       tvs.modtime = make_unix_date2(pdata+12);
1301       size = IVAL(pdata,16);
1302       mode = IVAL(pdata,24);
1303       break;
1304
1305     case SMB_SET_FILE_BASIC_INFO:
1306     {
1307       /* Ignore create time at offset pdata. */
1308
1309       /* access time */
1310       tvs.actime = interpret_long_date(pdata+8);
1311
1312       /* write time + changed time, combined. */
1313       tvs.modtime=MAX(interpret_long_date(pdata+16),
1314                       interpret_long_date(pdata+24));
1315
1316       /* attributes */
1317       mode = IVAL(pdata,32);
1318       break;
1319     }
1320
1321     case SMB_SET_FILE_END_OF_FILE_INFO:
1322     {
1323       if (IVAL(pdata,4) != 0)   /* more than 32 bits? */
1324          return(ERROR(ERRDOS,ERRunknownlevel));
1325       size = IVAL(pdata,0);
1326       break;
1327     }
1328
1329     case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
1330     case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
1331     default:
1332     {
1333       return(ERROR(ERRDOS,ERRunknownlevel));
1334     }
1335   }
1336
1337   DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
1338   DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
1339   DEBUG(6,("size: %x "   , size));
1340   DEBUG(6,("mode: %x\n"  , mode));
1341
1342   /* get some defaults (no modifications) if any info is zero. */
1343   if (!tvs.actime) tvs.actime = st.st_atime;
1344   if (!tvs.modtime) tvs.modtime = st.st_mtime;
1345   if (!size) size = st.st_size;
1346
1347   /* Try and set the times, size and mode of this file -
1348      if they are different from the current values
1349    */
1350   if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
1351   {
1352     if(sys_utime(fname, &tvs)!=0)
1353     {
1354       return(ERROR(ERRDOS,ERRnoaccess));
1355     }
1356   }
1357
1358   /* check the mode isn't different, before changing it */
1359   if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
1360   {
1361     DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
1362     return(ERROR(ERRDOS,ERRnoaccess));
1363   }
1364
1365   if(size != st.st_size)
1366   {
1367     if (fd == -1)
1368     {
1369       fd = sys_open(fname,O_RDWR,0);
1370       if (fd == -1)
1371       {
1372         return(ERROR(ERRDOS,ERRbadpath));
1373       }
1374       set_filelen(fd, size);
1375       close(fd);
1376     }
1377     else
1378     {
1379       set_filelen(fd, size);
1380     }
1381   }
1382
1383   SSVAL(params,0,0);
1384
1385   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1386   
1387   return(-1);
1388 }
1389
1390 /****************************************************************************
1391   reply to a TRANS2_MKDIR (make directory with extended attributes).
1392 ****************************************************************************/
1393 static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
1394                         int cnum, char **pparams, char **ppdata)
1395 {
1396   char *params = *pparams;
1397   pstring directory;
1398   int ret = -1;
1399
1400   if (!CAN_WRITE(cnum))
1401     return(ERROR(ERRSRV,ERRaccess));
1402
1403   strcpy(directory, &params[4]);
1404
1405   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
1406
1407   unix_convert(directory,cnum,0);
1408   if (check_name(directory,cnum))
1409     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
1410   
1411   if(ret < 0)
1412     {
1413       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
1414       return(UNIXERROR(ERRDOS,ERRnoaccess));
1415     }
1416
1417   /* Realloc the parameter and data sizes */
1418   params = *pparams = Realloc(*pparams,2);
1419   if(params == NULL)
1420     return(ERROR(ERRDOS,ERRnomem));
1421
1422   SSVAL(params,0,0);
1423
1424   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1425   
1426   return(-1);
1427 }
1428
1429 /****************************************************************************
1430   reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes)
1431   We don't actually do this - we just send a null response.
1432 ****************************************************************************/
1433 static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int bufsize,
1434                         int cnum, char **pparams, char **ppdata)
1435 {
1436   static uint16 fnf_handle = 257;
1437   char *params = *pparams;
1438   uint16 info_level = SVAL(params,4);
1439
1440   DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
1441
1442   switch (info_level) 
1443     {
1444     case 1:
1445     case 2:
1446       break;
1447     default:
1448       return(ERROR(ERRDOS,ERRunknownlevel));
1449     }
1450
1451   /* Realloc the parameter and data sizes */
1452   params = *pparams = Realloc(*pparams,6);
1453   if(params == NULL)
1454     return(ERROR(ERRDOS,ERRnomem));
1455
1456   SSVAL(params,0,fnf_handle);
1457   SSVAL(params,2,0); /* No changes */
1458   SSVAL(params,4,0); /* No EA errors */
1459
1460   fnf_handle++;
1461
1462   if(fnf_handle == 0)
1463     fnf_handle = 257;
1464
1465   send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
1466   
1467   return(-1);
1468 }
1469
1470 /****************************************************************************
1471   reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for 
1472   changes). Currently this does nothing.
1473 ****************************************************************************/
1474 static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int bufsize,
1475                         int cnum, char **pparams, char **ppdata)
1476 {
1477   char *params = *pparams;
1478
1479   DEBUG(3,("call_trans2findnotifynext\n"));
1480
1481   /* Realloc the parameter and data sizes */
1482   params = *pparams = Realloc(*pparams,4);
1483   if(params == NULL)
1484     return(ERROR(ERRDOS,ERRnomem));
1485
1486   SSVAL(params,0,0); /* No changes */
1487   SSVAL(params,2,0); /* No EA errors */
1488
1489   send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
1490   
1491   return(-1);
1492 }
1493
1494 /****************************************************************************
1495   reply to a SMBfindclose (stop trans2 directory search)
1496 ****************************************************************************/
1497 int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
1498 {
1499   int cnum;
1500   int outsize = 0;
1501   int16 dptr_num=SVALS(inbuf,smb_vwv0);
1502
1503   cnum = SVAL(inbuf,smb_tid);
1504
1505   DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1506
1507   dptr_close(dptr_num);
1508
1509   outsize = set_message(outbuf,0,0,True);
1510
1511   DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1512
1513   return(outsize);
1514 }
1515
1516 /****************************************************************************
1517   reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
1518 ****************************************************************************/
1519 int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
1520 {
1521   int cnum;
1522   int outsize = 0;
1523   int dptr_num= -1;
1524
1525   cnum = SVAL(inbuf,smb_tid);
1526   dptr_num = SVAL(inbuf,smb_vwv0);
1527
1528   DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1529
1530   /* We never give out valid handles for a 
1531      findnotifyfirst - so any dptr_num is ok here. 
1532      Just ignore it. */
1533
1534   outsize = set_message(outbuf,0,0,True);
1535
1536   DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1537
1538   return(outsize);
1539 }
1540
1541
1542 /****************************************************************************
1543   reply to a SMBtranss2 - just ignore it!
1544 ****************************************************************************/
1545 int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize)
1546 {
1547   DEBUG(4,("Ignoring transs2 of length %d\n",length));
1548   return(-1);
1549 }
1550
1551 /****************************************************************************
1552   reply to a SMBtrans2
1553 ****************************************************************************/
1554 int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
1555 {
1556   int outsize = 0;
1557   int cnum = SVAL(inbuf,smb_tid);
1558   unsigned int total_params = SVAL(inbuf, smb_tpscnt);
1559   unsigned int total_data =SVAL(inbuf, smb_tdscnt);
1560 #if 0
1561   unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
1562   unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
1563   unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
1564   BOOL close_tid = BITSETW(inbuf+smb_flags,0);
1565   BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
1566   int32 timeout = IVALS(inbuf,smb_timeout);
1567 #endif
1568   unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
1569   unsigned int tran_call = SVAL(inbuf, smb_setup0);
1570   char *params = NULL, *data = NULL;
1571   int num_params, num_params_sofar, num_data, num_data_sofar;
1572
1573   outsize = set_message(outbuf,0,0,True);
1574
1575   /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
1576      is so as a sanity check */
1577   if(suwcnt != 1 )
1578     {
1579       DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
1580       return(ERROR(ERRSRV,ERRerror));
1581     }
1582     
1583   /* Allocate the space for the maximum needed parameters and data */
1584   if (total_params > 0)
1585     params = (char *)malloc(total_params);
1586   if (total_data > 0)
1587     data = (char *)malloc(total_data);
1588   
1589   if ((total_params && !params)  || (total_data && !data))
1590     {
1591       DEBUG(2,("Out of memory in reply_trans2\n"));
1592       return(ERROR(ERRDOS,ERRnomem));
1593     }
1594
1595   /* Copy the param and data bytes sent with this request into
1596      the params buffer */
1597   num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
1598   num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
1599
1600   memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
1601   memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
1602
1603   if(num_data_sofar < total_data || num_params_sofar < total_params)
1604     {
1605     /* We need to send an interim response then receive the rest
1606        of the parameter/data bytes */
1607       outsize = set_message(outbuf,0,0,True);
1608       send_smb(Client,outbuf);
1609
1610       while( num_data_sofar < total_data || num_params_sofar < total_params)
1611         {
1612           if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
1613              CVAL(inbuf, smb_com) != SMBtranss2)
1614             {
1615               outsize = set_message(outbuf,0,0,True);
1616               DEBUG(2,("Invalid secondary trans2 packet\n"));
1617               free(params);
1618               free(data);
1619               return(ERROR(ERRSRV,ERRerror));
1620             }
1621       
1622           /* Revise total_params and total_data in case they have changed downwards */
1623           total_params = SVAL(inbuf, smb_tpscnt);
1624           total_data = SVAL(inbuf, smb_tdscnt);
1625           num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
1626           num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
1627           memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
1628                  smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
1629           memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
1630                  smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
1631         }
1632     }
1633
1634   if (Protocol >= PROTOCOL_NT1) {
1635     uint16 flg2 = SVAL(outbuf,smb_flg2);
1636     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1637   }
1638
1639   /* Now we must call the relevant TRANS2 function */
1640   switch(tran_call) 
1641     {
1642     case TRANSACT2_OPEN:
1643       outsize = call_trans2open(inbuf, outbuf, bufsize, cnum, &params, &data);
1644       break;
1645     case TRANSACT2_FINDFIRST:
1646       outsize = call_trans2findfirst(inbuf, outbuf, bufsize, cnum, &params, &data);
1647       break;
1648     case TRANSACT2_FINDNEXT:
1649       outsize = call_trans2findnext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1650       break;
1651     case TRANSACT2_QFSINFO:
1652       outsize = call_trans2qfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1653       break;
1654     case TRANSACT2_SETFSINFO:
1655       outsize = call_trans2setfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1656       break;
1657     case TRANSACT2_QPATHINFO:
1658     case TRANSACT2_QFILEINFO:
1659       outsize = call_trans2qfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1660       break;
1661     case TRANSACT2_SETPATHINFO:
1662     case TRANSACT2_SETFILEINFO:
1663       outsize = call_trans2setfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1664       break;
1665     case TRANSACT2_FINDNOTIFYFIRST:
1666       outsize = call_trans2findnotifyfirst(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1667       break;
1668     case TRANSACT2_FINDNOTIFYNEXT:
1669       outsize = call_trans2findnotifynext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1670       break;
1671     case TRANSACT2_MKDIR:
1672       outsize = call_trans2mkdir(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1673       break;
1674     default:
1675       /* Error in request */
1676       DEBUG(2,("%s Unknown request %d in trans2 call\n",timestring(), tran_call));
1677       if(params)
1678         free(params);
1679       if(data)
1680         free(data);
1681       return (ERROR(ERRSRV,ERRerror));
1682     }
1683
1684   /* As we do not know how many data packets will need to be
1685      returned here the various call_trans2xxxx calls
1686      must send their own. Thus a call_trans2xxx routine only
1687      returns a value other than -1 when it wants to send
1688      an error packet. 
1689   */
1690
1691   if(params)
1692     free(params);
1693   if(data)
1694     free(data);
1695   return outsize; /* If a correct response was needed the call_trans2xxx 
1696                      calls have already sent it. If outsize != -1 then it is
1697                      returning an error packet. */
1698 }