local.h: Removed ununsed SHARE_MODES_XXX defines. Upped SMBD_RELOAD_CHECK
[samba.git] / source / smbd / trans2.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    SMB transaction2 handling
5    Copyright (C) Jeremy Allison 1994-1997
6
7    Extensively modified by Andrew Tridgell, 1995
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "trans2.h"
26
27 extern int DEBUGLEVEL;
28 extern int Protocol;
29 extern connection_struct Connections[];
30 extern files_struct Files[];
31 extern BOOL case_sensitive;
32 extern int Client;
33
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 SMB_INFO_STANDARD:
1074     case SMB_INFO_QUERY_EA_SIZE:
1075       data_size = (info_level==1?22:26);
1076       put_dos_date2(pdata,l1_fdateCreation,sbuf.st_ctime); /* create = inode mod */
1077       put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime); /* access time */
1078       put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
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 SMB_INFO_QUERY_EAS_FROM_LIST:
1086       data_size = 24;
1087       put_dos_date2(pdata,0,sbuf.st_ctime); /* create time = inode mod time */
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 SMB_INFO_QUERY_ALL_EAS:
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; /* w95 returns 40 bytes not 36 - why ?. */
1105       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1106       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1107       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1108       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1109       SIVAL(pdata,32,mode);
1110
1111       DEBUG(5,("SMB_QFBI - "));
1112       DEBUG(5,("create: %s ", ctime(&sbuf.st_ctime)));
1113       DEBUG(5,("access: %s ", ctime(&sbuf.st_atime)));
1114       DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
1115       DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
1116       DEBUG(5,("mode: %x\n", mode));
1117
1118       break;
1119
1120     case SMB_QUERY_FILE_STANDARD_INFO:
1121       data_size = 22;
1122       SIVAL(pdata,0,size);
1123       SIVAL(pdata,8,size);
1124       SIVAL(pdata,16,sbuf.st_nlink);
1125       CVAL(pdata,20) = 0;
1126       CVAL(pdata,21) = (mode&aDIR)?1:0;
1127       break;
1128
1129     case SMB_QUERY_FILE_EA_INFO:
1130       data_size = 4;
1131       break;
1132
1133     case SMB_QUERY_FILE_NAME_INFO:
1134     case SMB_QUERY_FILE_ALT_NAME_INFO:
1135       data_size = 4 + l;
1136       SIVAL(pdata,0,l);
1137       strcpy(pdata+4,fname);
1138       break;
1139     case SMB_QUERY_FILE_ALLOCATION_INFO:
1140     case SMB_QUERY_FILE_END_OF_FILEINFO:
1141       data_size = 8;
1142       SIVAL(pdata,0,size);
1143       break;
1144
1145     case SMB_QUERY_FILE_ALL_INFO:
1146       put_long_date(pdata,sbuf.st_ctime); /* create time = inode mod time */
1147       put_long_date(pdata+8,sbuf.st_atime); /* access time */
1148       put_long_date(pdata+16,sbuf.st_mtime); /* write time */
1149       put_long_date(pdata+24,sbuf.st_mtime); /* change time */
1150       SIVAL(pdata,32,mode);
1151       pdata += 40;
1152       SIVAL(pdata,0,size);
1153       SIVAL(pdata,8,size);
1154       SIVAL(pdata,16,sbuf.st_nlink);
1155       CVAL(pdata,20) = 0;
1156       CVAL(pdata,21) = (mode&aDIR)?1:0;
1157       pdata += 24;
1158       pdata += 8; /* index number */
1159       pdata += 4; /* EA info */
1160       if (mode & aRONLY)
1161         SIVAL(pdata,0,0xA9);
1162       else
1163         SIVAL(pdata,0,0xd01BF);
1164       pdata += 4;
1165       SIVAL(pdata,0,pos); /* current offset */
1166       pdata += 8;
1167       SIVAL(pdata,0,mode); /* is this the right sort of mode info? */
1168       pdata += 4;
1169       pdata += 4; /* alignment */
1170       SIVAL(pdata,0,l);
1171       strcpy(pdata+4,fname);
1172       pdata += 4 + l;
1173       data_size = PTR_DIFF(pdata,(*ppdata));
1174       break;
1175
1176     case SMB_QUERY_FILE_STREAM_INFO:
1177       data_size = 24 + l;
1178       SIVAL(pdata,0,pos);
1179       SIVAL(pdata,4,size);
1180       SIVAL(pdata,12,size);
1181       SIVAL(pdata,20,l);        
1182       strcpy(pdata+24,fname);
1183       break;
1184     default:
1185       return(ERROR(ERRDOS,ERRunknownlevel));
1186     }
1187
1188   send_trans2_replies( outbuf, bufsize, params, 2, *ppdata, data_size);
1189
1190   return(-1);
1191 }
1192
1193 /****************************************************************************
1194   reply to a TRANS2_SETFILEINFO (set file info by fileid)
1195 ****************************************************************************/
1196 static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, 
1197                                       int bufsize, int cnum, char **pparams, 
1198                                       char **ppdata, int total_data)
1199 {
1200   char *params = *pparams;
1201   char *pdata = *ppdata;
1202   uint16 tran_call = SVAL(inbuf, smb_setup0);
1203   uint16 info_level;
1204   int mode=0;
1205   int size=0;
1206   struct utimbuf tvs;
1207   struct stat st;
1208   pstring fname1;
1209   char *fname;
1210   int fd = -1;
1211
1212   if (!CAN_WRITE(cnum))
1213     return(ERROR(ERRSRV,ERRaccess));
1214
1215   if (tran_call == TRANSACT2_SETFILEINFO) {
1216     int16 fnum = SVALS(params,0);
1217     info_level = SVAL(params,2);    
1218
1219     CHECK_FNUM(fnum,cnum);
1220     CHECK_ERROR(fnum);
1221
1222     fname = Files[fnum].name;
1223     fd = Files[fnum].fd_ptr->fd;
1224
1225     if(fstat(fd,&st)!=0) {
1226       DEBUG(3,("fstat of %s failed (%s)\n", fname, strerror(errno)));
1227       return(ERROR(ERRDOS,ERRbadpath));
1228     }
1229   } else {
1230     /* set path info */
1231     info_level = SVAL(params,0);    
1232     fname = fname1;
1233     strcpy(fname,&params[6]);
1234     unix_convert(fname,cnum,0);
1235     if(!check_name(fname, cnum))
1236       return(ERROR(ERRDOS,ERRbadpath));
1237     
1238     if(sys_stat(fname,&st)!=0) {
1239       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
1240       return(ERROR(ERRDOS,ERRbadpath));
1241     }    
1242   }
1243
1244   DEBUG(3,("call_trans2setfilepathinfo(%d) %s info_level=%d totdata=%d\n",
1245            tran_call,fname,info_level,total_data));
1246
1247   /* Realloc the parameter and data sizes */
1248   params = *pparams = Realloc(*pparams,2); SSVAL(params,0,0);
1249   if(params == NULL)
1250     return(ERROR(ERRDOS,ERRnomem));
1251
1252   size = st.st_size;
1253   tvs.modtime = st.st_mtime;
1254   tvs.actime = st.st_atime;
1255   mode = dos_mode(cnum,fname,&st);
1256
1257   if (total_data > 0 && IVAL(pdata,0) == total_data) {
1258     /* uggh, EAs for OS2 */
1259     DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
1260     SSVAL(params,0,ERROR_EAS_NOT_SUPPORTED);
1261
1262     send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1263   
1264     return(-1);    
1265   }
1266
1267   switch (info_level)
1268   {
1269     case SMB_INFO_STANDARD:
1270     case SMB_INFO_QUERY_EA_SIZE:
1271     {
1272       /* access time */
1273       tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
1274
1275       /* write time */
1276       tvs.modtime = make_unix_date2(pdata+l1_fdateLastWrite);
1277
1278       mode = SVAL(pdata,l1_attrFile);
1279       size = IVAL(pdata,l1_cbFile);
1280       break;
1281     }
1282
1283     /* XXXX um, i don't think this is right.
1284        it's also not in the cifs6.txt spec.
1285      */
1286     case SMB_INFO_QUERY_EAS_FROM_LIST:
1287       tvs.actime = make_unix_date2(pdata+8);
1288       tvs.modtime = make_unix_date2(pdata+12);
1289       size = IVAL(pdata,16);
1290       mode = IVAL(pdata,24);
1291       break;
1292
1293     /* XXXX nor this.  not in cifs6.txt, either. */
1294     case SMB_INFO_QUERY_ALL_EAS:
1295       tvs.actime = make_unix_date2(pdata+8);
1296       tvs.modtime = make_unix_date2(pdata+12);
1297       size = IVAL(pdata,16);
1298       mode = IVAL(pdata,24);
1299       break;
1300
1301     case SMB_SET_FILE_BASIC_INFO:
1302     {
1303       /* Ignore create time at offset pdata. */
1304
1305       /* access time */
1306       tvs.actime = interpret_long_date(pdata+8);
1307
1308       /* write time + changed time, combined. */
1309       tvs.modtime=MAX(interpret_long_date(pdata+16),
1310                       interpret_long_date(pdata+24));
1311
1312       /* attributes */
1313       mode = IVAL(pdata,32);
1314       break;
1315     }
1316
1317     case SMB_SET_FILE_END_OF_FILE_INFO:
1318     {
1319       if (IVAL(pdata,4) != 0)   /* more than 32 bits? */
1320          return(ERROR(ERRDOS,ERRunknownlevel));
1321       size = IVAL(pdata,0);
1322       break;
1323     }
1324
1325     case SMB_SET_FILE_DISPOSITION_INFO: /* not supported yet */
1326     case SMB_SET_FILE_ALLOCATION_INFO: /* not supported yet */
1327     default:
1328     {
1329       return(ERROR(ERRDOS,ERRunknownlevel));
1330     }
1331   }
1332
1333   DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
1334   DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
1335   DEBUG(6,("size: %x "   , size));
1336   DEBUG(6,("mode: %x\n"  , mode));
1337
1338   /* get some defaults (no modifications) if any info is zero. */
1339   if (!tvs.actime) tvs.actime = st.st_atime;
1340   if (!tvs.modtime) tvs.modtime = st.st_mtime;
1341   if (!size) size = st.st_size;
1342
1343   /* Try and set the times, size and mode of this file -
1344      if they are different from the current values
1345    */
1346   if (st.st_mtime != tvs.modtime || st.st_atime != tvs.actime)
1347   {
1348     if(sys_utime(fname, &tvs)!=0)
1349     {
1350       return(ERROR(ERRDOS,ERRnoaccess));
1351     }
1352   }
1353
1354   /* check the mode isn't different, before changing it */
1355   if (mode != dos_mode(cnum, fname, &st) && dos_chmod(cnum, fname, mode, NULL))
1356   {
1357     DEBUG(2,("chmod of %s failed (%s)\n", fname, strerror(errno)));
1358     return(ERROR(ERRDOS,ERRnoaccess));
1359   }
1360
1361   if(size != st.st_size)
1362   {
1363     if (fd == -1)
1364     {
1365       fd = sys_open(fname,O_RDWR,0);
1366       if (fd == -1)
1367       {
1368         return(ERROR(ERRDOS,ERRbadpath));
1369       }
1370       set_filelen(fd, size);
1371       close(fd);
1372     }
1373     else
1374     {
1375       set_filelen(fd, size);
1376     }
1377   }
1378
1379   SSVAL(params,0,0);
1380
1381   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1382   
1383   return(-1);
1384 }
1385
1386 /****************************************************************************
1387   reply to a TRANS2_MKDIR (make directory with extended attributes).
1388 ****************************************************************************/
1389 static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
1390                         int cnum, char **pparams, char **ppdata)
1391 {
1392   char *params = *pparams;
1393   pstring directory;
1394   int ret = -1;
1395
1396   if (!CAN_WRITE(cnum))
1397     return(ERROR(ERRSRV,ERRaccess));
1398
1399   strcpy(directory, &params[4]);
1400
1401   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
1402
1403   unix_convert(directory,cnum,0);
1404   if (check_name(directory,cnum))
1405     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
1406   
1407   if(ret < 0)
1408     {
1409       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
1410       return(UNIXERROR(ERRDOS,ERRnoaccess));
1411     }
1412
1413   /* Realloc the parameter and data sizes */
1414   params = *pparams = Realloc(*pparams,2);
1415   if(params == NULL)
1416     return(ERROR(ERRDOS,ERRnomem));
1417
1418   SSVAL(params,0,0);
1419
1420   send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
1421   
1422   return(-1);
1423 }
1424
1425 /****************************************************************************
1426   reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes)
1427   We don't actually do this - we just send a null response.
1428 ****************************************************************************/
1429 static int call_trans2findnotifyfirst(char *inbuf, char *outbuf, int length, int bufsize,
1430                         int cnum, char **pparams, char **ppdata)
1431 {
1432   static uint16 fnf_handle = 257;
1433   char *params = *pparams;
1434   uint16 info_level = SVAL(params,4);
1435
1436   DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
1437
1438   switch (info_level) 
1439     {
1440     case 1:
1441     case 2:
1442       break;
1443     default:
1444       return(ERROR(ERRDOS,ERRunknownlevel));
1445     }
1446
1447   /* Realloc the parameter and data sizes */
1448   params = *pparams = Realloc(*pparams,6);
1449   if(params == NULL)
1450     return(ERROR(ERRDOS,ERRnomem));
1451
1452   SSVAL(params,0,fnf_handle);
1453   SSVAL(params,2,0); /* No changes */
1454   SSVAL(params,4,0); /* No EA errors */
1455
1456   fnf_handle++;
1457
1458   if(fnf_handle == 0)
1459     fnf_handle = 257;
1460
1461   send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0);
1462   
1463   return(-1);
1464 }
1465
1466 /****************************************************************************
1467   reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for 
1468   changes). Currently this does nothing.
1469 ****************************************************************************/
1470 static int call_trans2findnotifynext(char *inbuf, char *outbuf, int length, int bufsize,
1471                         int cnum, char **pparams, char **ppdata)
1472 {
1473   char *params = *pparams;
1474
1475   DEBUG(3,("call_trans2findnotifynext\n"));
1476
1477   /* Realloc the parameter and data sizes */
1478   params = *pparams = Realloc(*pparams,4);
1479   if(params == NULL)
1480     return(ERROR(ERRDOS,ERRnomem));
1481
1482   SSVAL(params,0,0); /* No changes */
1483   SSVAL(params,2,0); /* No EA errors */
1484
1485   send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0);
1486   
1487   return(-1);
1488 }
1489
1490 /****************************************************************************
1491   reply to a SMBfindclose (stop trans2 directory search)
1492 ****************************************************************************/
1493 int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize)
1494 {
1495   int cnum;
1496   int outsize = 0;
1497   int16 dptr_num=SVALS(inbuf,smb_vwv0);
1498
1499   cnum = SVAL(inbuf,smb_tid);
1500
1501   DEBUG(3,("reply_findclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1502
1503   dptr_close(dptr_num);
1504
1505   outsize = set_message(outbuf,0,0,True);
1506
1507   DEBUG(3,("%s SMBfindclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1508
1509   return(outsize);
1510 }
1511
1512 /****************************************************************************
1513   reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search)
1514 ****************************************************************************/
1515 int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize)
1516 {
1517   int cnum;
1518   int outsize = 0;
1519   int dptr_num= -1;
1520
1521   cnum = SVAL(inbuf,smb_tid);
1522   dptr_num = SVAL(inbuf,smb_vwv0);
1523
1524   DEBUG(3,("reply_findnclose, cnum = %d, dptr_num = %d\n", cnum, dptr_num));
1525
1526   /* We never give out valid handles for a 
1527      findnotifyfirst - so any dptr_num is ok here. 
1528      Just ignore it. */
1529
1530   outsize = set_message(outbuf,0,0,True);
1531
1532   DEBUG(3,("%s SMB_findnclose cnum=%d, dptr_num = %d\n",timestring(),cnum,dptr_num));
1533
1534   return(outsize);
1535 }
1536
1537
1538 /****************************************************************************
1539   reply to a SMBtranss2 - just ignore it!
1540 ****************************************************************************/
1541 int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize)
1542 {
1543   DEBUG(4,("Ignoring transs2 of length %d\n",length));
1544   return(-1);
1545 }
1546
1547 /****************************************************************************
1548   reply to a SMBtrans2
1549 ****************************************************************************/
1550 int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize)
1551 {
1552   int outsize = 0;
1553   int cnum = SVAL(inbuf,smb_tid);
1554   unsigned int total_params = SVAL(inbuf, smb_tpscnt);
1555   unsigned int total_data =SVAL(inbuf, smb_tdscnt);
1556 #if 0
1557   unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
1558   unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
1559   unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
1560   BOOL close_tid = BITSETW(inbuf+smb_flags,0);
1561   BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
1562   int32 timeout = IVALS(inbuf,smb_timeout);
1563 #endif
1564   unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
1565   unsigned int tran_call = SVAL(inbuf, smb_setup0);
1566   char *params = NULL, *data = NULL;
1567   int num_params, num_params_sofar, num_data, num_data_sofar;
1568
1569   outsize = set_message(outbuf,0,0,True);
1570
1571   /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
1572      is so as a sanity check */
1573   if(suwcnt != 1 )
1574     {
1575       DEBUG(2,("Invalid smb_sucnt in trans2 call\n"));
1576       return(ERROR(ERRSRV,ERRerror));
1577     }
1578     
1579   /* Allocate the space for the maximum needed parameters and data */
1580   if (total_params > 0)
1581     params = (char *)malloc(total_params);
1582   if (total_data > 0)
1583     data = (char *)malloc(total_data);
1584   
1585   if ((total_params && !params)  || (total_data && !data))
1586     {
1587       DEBUG(2,("Out of memory in reply_trans2\n"));
1588       return(ERROR(ERRDOS,ERRnomem));
1589     }
1590
1591   /* Copy the param and data bytes sent with this request into
1592      the params buffer */
1593   num_params = num_params_sofar = SVAL(inbuf,smb_pscnt);
1594   num_data = num_data_sofar = SVAL(inbuf, smb_dscnt);
1595
1596   memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
1597   memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
1598
1599   if(num_data_sofar < total_data || num_params_sofar < total_params)
1600     {
1601     /* We need to send an interim response then receive the rest
1602        of the parameter/data bytes */
1603       outsize = set_message(outbuf,0,0,True);
1604       send_smb(Client,outbuf);
1605
1606       while( num_data_sofar < total_data || num_params_sofar < total_params)
1607         {
1608           if(!receive_smb(Client,inbuf, SMB_SECONDARY_WAIT) ||
1609              CVAL(inbuf, smb_com) != SMBtranss2)
1610             {
1611               outsize = set_message(outbuf,0,0,True);
1612               DEBUG(2,("Invalid secondary trans2 packet\n"));
1613               free(params);
1614               free(data);
1615               return(ERROR(ERRSRV,ERRerror));
1616             }
1617       
1618           /* Revise total_params and total_data in case they have changed downwards */
1619           total_params = SVAL(inbuf, smb_tpscnt);
1620           total_data = SVAL(inbuf, smb_tdscnt);
1621           num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
1622           num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
1623           memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
1624                  smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
1625           memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
1626                  smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
1627         }
1628     }
1629
1630   if (Protocol >= PROTOCOL_NT1) {
1631     uint16 flg2 = SVAL(outbuf,smb_flg2);
1632     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1633   }
1634
1635   /* Now we must call the relevant TRANS2 function */
1636   switch(tran_call) 
1637     {
1638     case TRANSACT2_OPEN:
1639       outsize = call_trans2open(inbuf, outbuf, bufsize, cnum, &params, &data);
1640       break;
1641     case TRANSACT2_FINDFIRST:
1642       outsize = call_trans2findfirst(inbuf, outbuf, bufsize, cnum, &params, &data);
1643       break;
1644     case TRANSACT2_FINDNEXT:
1645       outsize = call_trans2findnext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1646       break;
1647     case TRANSACT2_QFSINFO:
1648       outsize = call_trans2qfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1649       break;
1650     case TRANSACT2_SETFSINFO:
1651       outsize = call_trans2setfsinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1652       break;
1653     case TRANSACT2_QPATHINFO:
1654     case TRANSACT2_QFILEINFO:
1655       outsize = call_trans2qfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1656       break;
1657     case TRANSACT2_SETPATHINFO:
1658     case TRANSACT2_SETFILEINFO:
1659       outsize = call_trans2setfilepathinfo(inbuf, outbuf, length, bufsize, cnum, &params, &data, total_data);
1660       break;
1661     case TRANSACT2_FINDNOTIFYFIRST:
1662       outsize = call_trans2findnotifyfirst(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1663       break;
1664     case TRANSACT2_FINDNOTIFYNEXT:
1665       outsize = call_trans2findnotifynext(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1666       break;
1667     case TRANSACT2_MKDIR:
1668       outsize = call_trans2mkdir(inbuf, outbuf, length, bufsize, cnum, &params, &data);
1669       break;
1670     default:
1671       /* Error in request */
1672       DEBUG(2,("%s Unknown request %d in trans2 call\n",timestring(), tran_call));
1673       if(params)
1674         free(params);
1675       if(data)
1676         free(data);
1677       return (ERROR(ERRSRV,ERRerror));
1678     }
1679
1680   /* As we do not know how many data packets will need to be
1681      returned here the various call_trans2xxxx calls
1682      must send their own. Thus a call_trans2xxx routine only
1683      returns a value other than -1 when it wants to send
1684      an error packet. 
1685   */
1686
1687   if(params)
1688     free(params);
1689   if(data)
1690     free(data);
1691   return outsize; /* If a correct response was needed the call_trans2xxx 
1692                      calls have already sent it. If outsize != -1 then it is
1693                      returning an error packet. */
1694 }