From: Volker Lendecke Date: Fri, 28 Feb 2020 10:10:47 +0000 (+0100) Subject: libsmb: Implement SMB_FIND_FILE_UNIX_INFO2 dir listing X-Git-Tag: ldb-2.2.0~1524 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=890c94d5852c445cc866dd61fbfbcc8596726302;p=thirdparty%2Fsamba.git libsmb: Implement SMB_FIND_FILE_UNIX_INFO2 dir listing This keeps the original SMB_STRUCT_STAT coming from posix as part of struct file_info. It is a slight waste of space, as the timestamps are kept twice, but having a full SMB_STRUCT_STAT with the nlink!=0 validity check makes thinking about which mode/size/etc is the correct one a no-brainer. We can save space later by referencing only one set of time stamps for example. This for the time fixes readdirplus2, but for the wrong reason: We don't yet create files the "proper" way using posix create. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- diff --git a/selftest/knownfail.d/libsmbclient b/selftest/knownfail.d/libsmbclient index 8d8ef3cbaa2..e69de29bb2d 100644 --- a/selftest/knownfail.d/libsmbclient +++ b/selftest/knownfail.d/libsmbclient @@ -1,2 +0,0 @@ -samba4.unix_ext.libsmbclient.readdirplus2.NT1.readdirplus2.* -samba4.unix_ext.libsmbclient.readdirplus_seek.NT1.readdirplus_seek.* diff --git a/source3/include/client.h b/source3/include/client.h index 23ba86d2a2c..34b6a9fc383 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -114,6 +114,12 @@ struct file_info { struct timespec mtime_ts; struct timespec atime_ts; struct timespec ctime_ts; + + /* + * Native sbuf from posix extensions. Valid if st_ex_nlink!=0. + */ + SMB_STRUCT_STAT posix_sbuf; + char *name; char *short_name; }; diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index f868e72a239..ca6d8b53129 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -305,6 +305,63 @@ static size_t interpret_long_filename(TALLOC_CTX *ctx, } return calc_next_entry_offset(base, pdata_end); } + case SMB_FIND_FILE_UNIX_INFO2: + { + SMB_STRUCT_STAT *sbuf = &finfo->posix_sbuf; + size_t namelen; + + if (pdata_end - base < 128) { + return pdata_end - base; + } + + p += 4; /* next entry offset */ + + if (p_resume_key) { + *p_resume_key = IVAL(p,0); + } + p += 4; /* fileindex */ + + fetch_file_unix_basic_info2((const uint8_t *)p, sbuf); + p += 116; + + finfo->mode = S_ISDIR(sbuf->st_ex_mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_NORMAL; + if (sbuf->st_ex_mode & S_IXUSR) { + finfo->mode |= FILE_ATTRIBUTE_ARCHIVE; + } + + finfo->size = sbuf->st_ex_size; + finfo->allocated_size = + sbuf->st_ex_blksize * sbuf->st_ex_blocks; + finfo->uid = sbuf->st_ex_uid; + finfo->gid = sbuf->st_ex_gid; + finfo->ino = sbuf->st_ex_ino; + finfo->btime_ts = sbuf->st_ex_btime; + finfo->mtime_ts = sbuf->st_ex_mtime; + finfo->atime_ts = sbuf->st_ex_atime; + finfo->ctime_ts = sbuf->st_ex_ctime; + + namelen = IVAL(p, 0); + p += 4; + + if (namelen > (pdata_end - p)) { + return pdata_end - base; + } + + ret = clistr_pull_talloc( + ctx, + base_ptr, + recv_flags2, + &finfo->name, + p, + namelen, + 0); + if (ret == (size_t)-1) { + return pdata_end - base; + } + return calc_next_entry_offset(base, pdata_end); + } } DEBUG(1,("Unknown long filename format %d\n",level)); @@ -1043,6 +1100,7 @@ NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute, NTSTATUS status = NT_STATUS_NO_MEMORY; struct file_info *finfo; size_t i, num_finfo = 0; + uint32_t caps; uint16_t info_level; if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { @@ -1063,8 +1121,15 @@ NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16_t attribute, goto fail; } - info_level = (smb1cli_conn_capabilities(cli->conn) & CAP_NT_SMBS) - ? SMB_FIND_FILE_BOTH_DIRECTORY_INFO : SMB_FIND_INFO_STANDARD; + caps = smb1cli_conn_capabilities(cli->conn); + + if (caps & CAP_UNIX) { + info_level = SMB_FIND_FILE_UNIX_INFO2; + } else if (caps & CAP_NT_SMBS) { + info_level = SMB_FIND_FILE_BOTH_DIRECTORY_INFO; + } else { + info_level = SMB_FIND_INFO_STANDARD; + } req = cli_list_send(frame, ev, cli, mask, attribute, info_level); if (req == NULL) {