summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/libsmb/clilist.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c
index 892a457255..a1434338c9 100644
--- a/source3/libsmb/clilist.c
+++ b/source3/libsmb/clilist.c
@@ -31,16 +31,20 @@ extern file_info def_finfo;
by NT and 2 is used by OS/2
****************************************************************************/
-static size_t interpret_long_filename(struct cli_state *cli,
- int level,char *p,file_info *finfo, uint32 *p_resume_key)
+static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,file_info *finfo,
+ uint32 *p_resume_key, DATA_BLOB *p_last_name_raw, uint32 *p_last_name_raw_len)
{
file_info finfo2;
int len;
char *base = p;
- if (!finfo) finfo = &finfo2;
+ if (!finfo) {
+ finfo = &finfo2;
+ }
- *p_resume_key = 0;
+ if (p_resume_key) {
+ *p_resume_key = 0;
+ }
memcpy(finfo,&def_finfo,sizeof(*finfo));
switch (level) {
@@ -87,7 +91,9 @@ static size_t interpret_long_filename(struct cli_state *cli,
size_t namelen, slen;
p += 4; /* next entry offset */
- *p_resume_key = IVAL(p,0);
+ if (p_resume_key) {
+ *p_resume_key = IVAL(p,0);
+ }
p += 4; /* fileindex */
/* these dates appear to arrive in a
@@ -134,6 +140,22 @@ static size_t interpret_long_filename(struct cli_state *cli,
clistr_pull(cli, finfo->name, p,
sizeof(finfo->name),
namelen, 0);
+
+ /* To be robust in the face of unicode conversion failures
+ we need to copy the raw bytes of the last name seen here.
+ Namelen doesn't include the terminating unicode null, so
+ copy it here. */
+
+ if (p_last_name_raw && p_last_name_raw_len) {
+ if (namelen + 2 > p_last_name_raw->length) {
+ memset(p_last_name_raw->data, '\0', sizeof(p_last_name_raw->length));
+ *p_last_name_raw_len = 0;
+ } else {
+ memcpy(p_last_name_raw->data, p, namelen);
+ SSVAL(p_last_name_raw->data, namelen, 0);
+ *p_last_name_raw_len = namelen + 2;
+ }
+ }
return (size_t)IVAL(base, 0);
}
}
@@ -174,6 +196,8 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
pstring param;
const char *mnt;
uint32 resume_key = 0;
+ uint32 last_name_raw_len = 0;
+ DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring));
/* NT uses 260, OS/2 uses 2. Both accept 1. */
info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
@@ -215,8 +239,12 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
can miss filenames. Use last filename continue instead. JRA */
SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END)); /* resume required + close on end */
p = param+12;
- p += clistr_push(cli, param+12, mask, sizeof(param)-12,
- STR_TERMINATE);
+ if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) {
+ memcpy(p, last_name_raw.data, last_name_raw_len);
+ p += last_name_raw_len;
+ } else {
+ p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE);
+ }
}
param_len = PTR_DIFF(p, param);
@@ -283,7 +311,8 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
/* Last entry - fixup the last offset length. */
SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
}
- p2 += interpret_long_filename(cli,info_level,p2,&finfo,&resume_key);
+ p2 += interpret_long_filename(cli,info_level,p2,&finfo,
+ &resume_key,&last_name_raw,&last_name_raw_len);
}
if (ff_lastname > 0) {
@@ -323,12 +352,13 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
mnt = cli_cm_get_mntpoint( cli );
for (p=dirlist,i=0;i<total_received;i++) {
- p += interpret_long_filename(cli,info_level,p,&finfo,&resume_key);
+ p += interpret_long_filename(cli,info_level,p,&finfo,NULL,NULL,NULL);
fn( mnt,&finfo, Mask, state );
}
- /* free up the dirlist buffer */
+ /* free up the dirlist buffer and last name raw blob */
SAFE_FREE(dirlist);
+ data_blob_free(&last_name_raw);
return(total_received);
}