Ignore:
Timestamp:
Jul 26, 2016, 12:07:18 PM (9 years ago)
Author:
Paul Smedley
Message:

Support file listings on SMB2+ connections

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/client-3.0/src/smbwrp.c

    r939 r940  
    916916}
    917917
     918/***************************************************************
     919 Wrapper that allows SMB2 to list a directory.
     920 Synchronous only.
     921 Based on cli_smb2_list
     922***************************************************************/
     923
     924NTSTATUS list_files_smb2(struct cli_state *cli,
     925                        const char *pathname,
     926                        uint16_t attribute,
     927                        NTSTATUS (*fn)(const char *,
     928                                struct smbwrp_fileinfo *,
     929                                const char *,
     930                                void *),
     931                        void *state)
     932{
     933        NTSTATUS status;
     934        uint16_t fnum = 0xffff;
     935        char *parent_dir = NULL;
     936        const char *mask = NULL;
     937        struct smb2_hnd *ph = NULL;
     938        bool processed_file = false;
     939        TALLOC_CTX *frame = talloc_stackframe();
     940        TALLOC_CTX *subframe = NULL;
     941        bool mask_has_wild;
     942        void *dircachectx = NULL;
     943        smbwrp_fileinfo wrpfinfo;
     944
     945        if (smbXcli_conn_has_async_calls(cli->conn)) {
     946                /*
     947                 * Can't use sync call while an async call is in flight
     948                 */
     949                status = NT_STATUS_INVALID_PARAMETER;
     950                goto fail;
     951        }
     952
     953        if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
     954                status = NT_STATUS_INVALID_PARAMETER;
     955                goto fail;
     956        }
     957
     958        /* Get the directory name. */
     959        if (!windows_parent_dirname(frame,
     960                                pathname,
     961                                &parent_dir,
     962                                &mask)) {
     963                status = NT_STATUS_NO_MEMORY;
     964                goto fail;
     965        }
     966
     967        mask_has_wild = ms_has_wild(mask);
     968
     969        status = cli_smb2_create_fnum(cli,
     970                        parent_dir,
     971                        0,                      /* create_flags */
     972                        SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */
     973                        FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
     974                        FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */
     975                        FILE_OPEN,              /* create_disposition */
     976                        FILE_DIRECTORY_FILE,    /* create_options */
     977                        &fnum,
     978                        NULL);
     979
     980        if (!NT_STATUS_IS_OK(status)) {
     981                goto fail;
     982        }
     983
     984        status = map_fnum_to_smb2_handle(cli,
     985                                        fnum,
     986                                        &ph);
     987        if (!NT_STATUS_IS_OK(status)) {
     988                goto fail;
     989        }
     990
     991        do {
     992                uint8_t *dir_data = NULL;
     993                uint32_t dir_data_length = 0;
     994                uint32_t next_offset = 0;
     995                subframe = talloc_stackframe();
     996
     997                status = smb2cli_query_directory(cli->conn,
     998                                        cli->timeout,
     999                                        cli->smb2.session,
     1000                                        cli->smb2.tcon,
     1001                                        SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
     1002                                        0,      /* flags */
     1003                                        0,      /* file_index */
     1004                                        ph->fid_persistent,
     1005                                        ph->fid_volatile,
     1006                                        mask,
     1007                                        0xffff,
     1008                                        subframe,
     1009                                        &dir_data,
     1010                                        &dir_data_length);
     1011
     1012                if (!NT_STATUS_IS_OK(status)) {
     1013                        if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     1014                                break;
     1015                        }
     1016                        goto fail;
     1017                }
     1018
     1019                do {
     1020                        struct file_info *finfo = talloc_zero(subframe,
     1021                                                        struct file_info);
     1022
     1023                        if (finfo == NULL) {
     1024                                status = NT_STATUS_NO_MEMORY;
     1025                                goto fail;
     1026                        }
     1027
     1028                        status = parse_finfo_id_both_directory_info(dir_data,
     1029                                                dir_data_length,
     1030                                                finfo,
     1031                                                &next_offset);
     1032
     1033                        if (!NT_STATUS_IS_OK(status)) {
     1034                                goto fail;
     1035                        }
     1036
     1037                        if (dir_check_ftype((uint32_t)finfo->mode,
     1038                                        (uint32_t)attribute)) {
     1039                                /*
     1040                                 * Only process if attributes match.
     1041                                 * On SMB1 server does this, so on
     1042                                 * SMB2 we need to emulate in the
     1043                                 * client.
     1044                                 *
     1045                                 * https://bugzilla.samba.org/show_bug.cgi?id=10260
     1046                                 */
     1047                                processed_file = true;
     1048
     1049                                //as samba and this client have different finfo, we need to convert
     1050                                memset(&wrpfinfo, 0, sizeof(wrpfinfo));
     1051                                wrpfinfo.size = finfo[0].size;
     1052                                wrpfinfo.attr = finfo[0].mode;
     1053                                wrpfinfo.ctime = convert_timespec_to_time_t(finfo[0].ctime_ts);
     1054                                wrpfinfo.mtime = convert_timespec_to_time_t(finfo[0].mtime_ts);
     1055                                wrpfinfo.atime = convert_timespec_to_time_t(finfo[0].atime_ts);
     1056                                wrpfinfo.easize = finfo[0].easize;
     1057                                strncpy(wrpfinfo.fname, finfo[0].name, sizeof(wrpfinfo.fname) -1);
     1058
     1059                                status = fn(cli->dfs_mountpoint,
     1060                                        &wrpfinfo,
     1061                                        pathname,
     1062                                        state);
     1063
     1064                                if (!NT_STATUS_IS_OK(status)) {
     1065                                        /* not sure why this is required on OS/2 */
     1066                                        if (status != NT_STATUS_WAIT_1)
     1067                                                break;
     1068                                }
     1069                        }
     1070
     1071                        TALLOC_FREE(finfo);
     1072
     1073                        /* Move to next entry. */
     1074                        if (next_offset) {
     1075                                dir_data += next_offset;
     1076                                dir_data_length -= next_offset;
     1077                        }
     1078                } while (next_offset != 0);
     1079
     1080                TALLOC_FREE(subframe);
     1081
     1082                if (!mask_has_wild) {
     1083                        /*
     1084                         * MacOSX 10 doesn't set STATUS_NO_MORE_FILES
     1085                         * when handed a non-wildcard path. Do it
     1086                         * for the server (with a non-wildcard path
     1087                         * there should only ever be one file returned.
     1088                         */
     1089                        status = STATUS_NO_MORE_FILES;
     1090                        break;
     1091                }
     1092
     1093        } while (NT_STATUS_IS_OK(status));
     1094
     1095        if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
     1096                status = NT_STATUS_OK;
     1097        }
     1098
     1099        if (NT_STATUS_IS_OK(status) && !processed_file) {
     1100                /*
     1101                 * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
     1102                 * if no files match. Emulate this in the client.
     1103                 */
     1104                status = NT_STATUS_NO_SUCH_FILE;
     1105        }
     1106
     1107  fail:
     1108
     1109        if (fnum != 0xffff) {
     1110                cli_smb2_close_fnum(cli, fnum);
     1111        }
     1112        TALLOC_FREE(subframe);
     1113        TALLOC_FREE(frame);
     1114        return status;
     1115}
     1116
     1117
    9181118/****************************************************************************
    9191119 Do a directory listing, calling fn on each file found.
     
    9331133        void *dircachectx = NULL;
    9341134        smbwrp_fileinfo wrpfinfo;
     1135
     1136        if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
     1137        debuglocal(4,"SMB2 detected, calling list_files_smb2()\n");
     1138                return list_files_smb2(cli, mask, attribute, fn, state);
    9351139
    9361140        /* Try to get the listing from cache. */
Note: See TracChangeset for help on using the changeset viewer.