2 Unix SMB/Netbios implementation.
4 client directory list routines
5 Copyright (C) Andrew Tridgell 1994-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 /****************************************************************************
28 interpret a long filename structure - this is mostly guesses at the moment
29 The length of the structure is returned
30 The structure of a long filename depends on the info level. 260 is used
31 by NT and 2 is used by OS/2
32 ****************************************************************************/
33 static int interpret_long_filename(int level,char *p,file_info *finfo)
35 extern file_info def_finfo;
38 memcpy(finfo,&def_finfo,sizeof(*finfo));
42 case 1: /* OS/2 understands this */
44 /* these dates are converted to GMT by make_unix_date */
45 finfo->ctime = make_unix_date2(p+4);
46 finfo->atime = make_unix_date2(p+8);
47 finfo->mtime = make_unix_date2(p+12);
48 finfo->size = IVAL(p,16);
49 finfo->mode = CVAL(p,24);
50 pstrcpy(finfo->name,p+27);
51 dos_to_unix(finfo->name,True);
53 return(28 + CVAL(p,26));
55 case 2: /* this is what OS/2 uses mostly */
57 /* these dates are converted to GMT by make_unix_date */
58 finfo->ctime = make_unix_date2(p+4);
59 finfo->atime = make_unix_date2(p+8);
60 finfo->mtime = make_unix_date2(p+12);
61 finfo->size = IVAL(p,16);
62 finfo->mode = CVAL(p,24);
63 pstrcpy(finfo->name,p+31);
64 dos_to_unix(finfo->name,True);
66 return(32 + CVAL(p,30));
68 /* levels 3 and 4 are untested */
71 /* these dates are probably like the other ones */
72 finfo->ctime = make_unix_date2(p+8);
73 finfo->atime = make_unix_date2(p+12);
74 finfo->mtime = make_unix_date2(p+16);
75 finfo->size = IVAL(p,20);
76 finfo->mode = CVAL(p,28);
77 pstrcpy(finfo->name,p+33);
78 dos_to_unix(finfo->name,True);
84 /* these dates are probably like the other ones */
85 finfo->ctime = make_unix_date2(p+8);
86 finfo->atime = make_unix_date2(p+12);
87 finfo->mtime = make_unix_date2(p+16);
88 finfo->size = IVAL(p,20);
89 finfo->mode = CVAL(p,28);
90 pstrcpy(finfo->name,p+37);
91 dos_to_unix(finfo->name,True);
95 case 260: /* NT uses this, but also accepts 2 */
99 p += 4; /* next entry offset */
100 p += 4; /* fileindex */
102 /* these dates appear to arrive in a
103 weird way. It seems to be localtime
104 plus the serverzone given in the
105 initial connect. This is GMT when
106 DST is not in effect and one hour
107 from GMT otherwise. Can this really
110 I suppose this could be called
111 kludge-GMT. Is is the GMT you get
112 by using the current DST setting on
113 a different localtime. It will be
114 cheap to calculate, I suppose, as
115 no DST tables will be needed */
117 finfo->ctime = interpret_long_date(p); p += 8;
118 finfo->atime = interpret_long_date(p); p += 8;
119 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
120 finfo->size = IVAL(p,0); p += 8;
121 p += 8; /* alloc size */
122 finfo->mode = CVAL(p,0); p += 4;
123 namelen = IVAL(p,0); p += 4;
124 p += 4; /* EA size */
125 p += 2; /* short name len? */
126 p += 24; /* short name? */
127 StrnCpy(finfo->name,p,MIN(sizeof(finfo->name)-1,namelen));
128 dos_to_unix(finfo->name,True);
134 DEBUG(1,("Unknown long filename format %d\n",level));
139 /****************************************************************************
140 do a directory listing, calling fn on each file found
141 ****************************************************************************/
142 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
143 void (*fn)(file_info *, const char *))
145 int max_matches = 512;
146 /* NT uses 260, OS/2 uses 2. Both accept 1. */
147 int info_level = cli->protocol<PROTOCOL_NT1?1:260;
152 char *dirlist = NULL;
154 int total_received = -1;
156 int ff_searchcount=0;
161 char *rparam=NULL, *rdata=NULL;
162 int param_len, data_len;
168 unix_to_dos(mask,True);
170 while (ff_eos == 0) {
172 if (loop_count > 200) {
173 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
177 param_len = 12+strlen(mask)+1;
180 setup = TRANSACT2_FINDFIRST;
181 SSVAL(param,0,attribute); /* attribute */
182 SSVAL(param,2,max_matches); /* max count */
183 SSVAL(param,4,4+2); /* resume required + close on end */
184 SSVAL(param,6,info_level);
186 pstrcpy(param+12,mask);
188 setup = TRANSACT2_FINDNEXT;
189 SSVAL(param,0,ff_dir_handle);
190 SSVAL(param,2,max_matches); /* max count */
191 SSVAL(param,4,info_level);
192 SIVAL(param,6,0); /* ff_resume_key */
193 SSVAL(param,10,8+4+2); /* continue + resume required + close on end */
194 pstrcpy(param+12,mask);
196 DEBUG(5,("hand=0x%X ff_lastname=%d mask=%s\n",
197 ff_dir_handle,ff_lastname,mask));
200 if (!cli_send_trans(cli, SMBtrans2,
201 NULL, 0, /* Name, length */
202 -1, 0, /* fid, flags */
203 &setup, 1, 0, /* setup, length, max */
204 param, param_len, 10, /* param, length, max */
206 cli->max_xmit /* data, length, max */
211 if (!cli_receive_trans(cli, SMBtrans2,
213 &rdata, &data_len)) {
214 /* we need to work around a Win95 bug - sometimes
215 it gives ERRSRV/ERRerror temprarily */
218 cli_error(cli, &eclass, &ecode, NULL);
219 if (eclass != ERRSRV || ecode != ERRerror) break;
224 if (total_received == -1) total_received = 0;
226 /* parse out some important return info */
229 ff_dir_handle = SVAL(p,0);
230 ff_searchcount = SVAL(p,2);
232 ff_lastname = SVAL(p,8);
234 ff_searchcount = SVAL(p,0);
236 ff_lastname = SVAL(p,6);
239 if (ff_searchcount == 0)
242 /* point to the data bytes */
245 /* we might need the lastname for continuations */
246 if (ff_lastname > 0) {
250 StrnCpy(mask,p+ff_lastname,
251 MIN(sizeof(mask)-1,data_len-ff_lastname));
254 pstrcpy(mask,p + ff_lastname + 1);
261 dos_to_unix(mask, True);
263 /* and add them to the dirlist pool */
264 dirlist = Realloc(dirlist,dirlist_len + data_len);
267 DEBUG(0,("Failed to expand dirlist\n"));
271 /* put in a length for the last entry, to ensure we can chain entries
272 into the next packet */
273 for (p2=p,i=0;i<(ff_searchcount-1);i++)
274 p2 += interpret_long_filename(info_level,p2,NULL);
275 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
277 /* grab the data for later use */
278 memcpy(dirlist+dirlist_len,p,data_len);
279 dirlist_len += data_len;
281 total_received += ff_searchcount;
283 if (rdata) free(rdata); rdata = NULL;
284 if (rparam) free(rparam); rparam = NULL;
286 DEBUG(3,("received %d entries (eos=%d)\n",
287 ff_searchcount,ff_eos));
289 if (ff_searchcount > 0) loop_count = 0;
294 for (p=dirlist,i=0;i<total_received;i++) {
295 p += interpret_long_filename(info_level,p,&finfo);
299 /* free up the dirlist buffer */
300 if (dirlist) free(dirlist);
301 return(total_received);