[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / libsmb / clilist.c
index e09a6514ad9f6dfc7ed8315bbc26f006c6120567..5da63096b13b48863d231c32072dd3bd6e98e013 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -44,14 +43,15 @@ static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,f
                *p_resume_key = 0;
        }
        memcpy(finfo,&def_finfo,sizeof(*finfo));
+       finfo->cli = cli;
 
        switch (level) {
                case 1: /* OS/2 understands this */
                        /* these dates are converted to GMT by
                            make_unix_date */
-                       finfo->ctime = cli_make_unix_date2(cli, p+4);
-                       finfo->atime = cli_make_unix_date2(cli, p+8);
-                       finfo->mtime = cli_make_unix_date2(cli, p+12);
+                       finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
+                       finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
+                       finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
                        finfo->size = IVAL(p,16);
                        finfo->mode = CVAL(p,24);
                        len = CVAL(p, 26);
@@ -70,9 +70,9 @@ static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,f
                case 2: /* this is what OS/2 uses mostly */
                        /* these dates are converted to GMT by
                            make_unix_date */
-                       finfo->ctime = cli_make_unix_date2(cli, p+4);
-                       finfo->atime = cli_make_unix_date2(cli, p+8);
-                       finfo->mtime = cli_make_unix_date2(cli, p+12);
+                       finfo->ctime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+4));
+                       finfo->atime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+8));
+                       finfo->mtime_ts = convert_time_t_to_timespec(cli_make_unix_date2(cli, p+12));
                        finfo->size = IVAL(p,16);
                        finfo->mode = CVAL(p,24);
                        len = CVAL(p, 30);
@@ -94,27 +94,13 @@ static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,f
                        }
                        p += 4; /* fileindex */
                                
-                       /* these dates appear to arrive in a
-                          weird way. It seems to be localtime
-                          plus the serverzone given in the
-                          initial connect. This is GMT when
-                          DST is not in effect and one hour
-                          from GMT otherwise. Can this really
-                          be right??
-                          
-                          I suppose this could be called
-                          kludge-GMT. Is is the GMT you get
-                          by using the current DST setting on
-                          a different localtime. It will be
-                          cheap to calculate, I suppose, as
-                          no DST tables will be needed */
-                       
-                       finfo->ctime = interpret_long_date(p);
+                       /* Offset zero is "create time", not "change time". */
                        p += 8;
-                       finfo->atime = interpret_long_date(p);
+                       finfo->atime_ts = interpret_long_date(p);
                        p += 8;
-                       finfo->mtime = interpret_long_date(p);
+                       finfo->mtime_ts = interpret_long_date(p);
                        p += 8;
+                       finfo->ctime_ts = interpret_long_date(p);
                        p += 8;
                        finfo->size = IVAL2_TO_SMB_BIG_UINT(p,0);
                        p += 8;
@@ -179,13 +165,12 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
        pstring mask;
        file_info finfo;
        int i;
-       char *tdl, *dirlist = NULL;
+       char *dirlist = NULL;
        int dirlist_len = 0;
        int total_received = -1;
        BOOL First = True;
        int ff_searchcount=0;
        int ff_eos=0;
-       int ff_lastname=0;
        int ff_dir_handle=0;
        int loop_count = 0;
        char *rparam=NULL, *rdata=NULL;
@@ -200,13 +185,7 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
        /* NT uses 260, OS/2 uses 2. Both accept 1. */
        info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
        
-       /* when getting a directory listing from a 2k dfs root share, 
-          we have to include the full path (\server\share\mask) here */
-          
-       if ( cli->dfsroot )
-               pstr_sprintf( mask, "\\%s\\%s\\%s", cli->desthost, cli->share, Mask );
-       else
-               pstrcpy(mask,Mask);
+       pstrcpy(mask,Mask);
        
        while (ff_eos == 0) {
                loop_count++;
@@ -271,6 +250,10 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                           it gives ERRSRV/ERRerror temprarily */
                        uint8 eclass;
                        uint32 ecode;
+
+                       SAFE_FREE(rdata);
+                       SAFE_FREE(rparam);
+
                        cli_dos_error(cli, &eclass, &ecode);
                        if (eclass != ERRSRV || ecode != ERRerror)
                                break;
@@ -278,8 +261,11 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                        continue;
                }
 
-                if (cli_is_error(cli) || !rdata || !rparam) 
+                if (cli_is_error(cli) || !rdata || !rparam) {
+                       SAFE_FREE(rdata);
+                       SAFE_FREE(rparam);
                        break;
+               }
 
                if (total_received == -1)
                        total_received = 0;
@@ -290,15 +276,16 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                        ff_dir_handle = SVAL(p,0);
                        ff_searchcount = SVAL(p,2);
                        ff_eos = SVAL(p,4);
-                       ff_lastname = SVAL(p,8);
                } else {
                        ff_searchcount = SVAL(p,0);
                        ff_eos = SVAL(p,2);
-                       ff_lastname = SVAL(p,6);
                }
 
-               if (ff_searchcount == 0) 
+               if (ff_searchcount == 0) {
+                       SAFE_FREE(rdata);
+                       SAFE_FREE(rparam);
                        break;
+               }
 
                /* point to the data bytes */
                p = rdata;
@@ -320,7 +307,7 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
                        }
                }
 
-               if (ff_lastname > 0) {
+               if (ff_searchcount > 0) {
                        pstrcpy(mask, finfo.name);
                } else {
                        pstrcpy(mask,"");
@@ -328,13 +315,13 @@ int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute,
 
                /* grab the data for later use */
                /* and add them to the dirlist pool */
-               tdl = SMB_REALLOC(dirlist,dirlist_len + data_len);
+               dirlist = (char *)SMB_REALLOC(dirlist,dirlist_len + data_len);
 
-               if (!tdl) {
+               if (!dirlist) {
                        DEBUG(0,("cli_list_new: Failed to expand dirlist\n"));
+                       SAFE_FREE(rdata);
+                       SAFE_FREE(rparam);
                        break;
-               } else {
-                       dirlist = tdl;
                }
 
                memcpy(dirlist+dirlist_len,p,data_len);
@@ -356,10 +343,17 @@ 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,NULL,NULL,NULL);
-               fn( mnt,&finfo, Mask, state );
-       }
+        /* see if the server disconnected or the connection otherwise failed */
+        if (cli_is_error(cli)) {
+                total_received = -1;
+        } else {
+                /* no connection problem.  let user function add each entry */
+                for (p=dirlist,i=0;i<total_received;i++) {
+                        p += interpret_long_filename(cli, info_level, p,
+                                                     &finfo,NULL,NULL,NULL);
+                        fn( mnt,&finfo, Mask, state );
+                }
+        }
 
        /* free up the dirlist buffer and last name raw blob */
        SAFE_FREE(dirlist);
@@ -377,11 +371,14 @@ static int interpret_short_filename(struct cli_state *cli, char *p,file_info *fi
 
        *finfo = def_finfo;
 
+       finfo->cli = cli;
        finfo->mode = CVAL(p,21);
        
        /* this date is converted to GMT by make_unix_date */
-       finfo->ctime = cli_make_unix_date(cli, p+22);
-       finfo->mtime = finfo->atime = finfo->ctime;
+       finfo->ctime_ts.tv_sec = cli_make_unix_date(cli, p+22);
+       finfo->ctime_ts.tv_nsec = 0;
+       finfo->mtime_ts.tv_sec = finfo->atime_ts.tv_sec = finfo->ctime_ts.tv_sec;
+       finfo->mtime_ts.tv_nsec = finfo->atime_ts.tv_nsec = 0;
        finfo->size = IVAL(p,26);
        clistr_pull(cli, finfo->name, p+30, sizeof(finfo->name), 12, STR_ASCII);
        if (strcmp(finfo->name, "..") && strcmp(finfo->name, ".")) {
@@ -409,7 +406,7 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
        int num_asked = (cli->max_xmit - 100)/DIR_STRUCT_SIZE;
        int num_received = 0;
        int i;
-       char *tdl, *dirlist = NULL;
+       char *dirlist = NULL;
        pstring mask;
        
        ZERO_ARRAY(status);
@@ -454,14 +451,12 @@ int cli_list_old(struct cli_state *cli,const char *Mask,uint16 attribute,
 
                first = False;
 
-               tdl = SMB_REALLOC(dirlist,(num_received + received)*DIR_STRUCT_SIZE);
-
-               if (!tdl) {
+               dirlist = (char *)SMB_REALLOC(
+                       dirlist,(num_received + received)*DIR_STRUCT_SIZE);
+               if (!dirlist) {
                        DEBUG(0,("cli_list_old: failed to expand dirlist"));
-                       SAFE_FREE(dirlist);
                        return 0;
                }
-               else dirlist = tdl;
 
                p = smb_buf(cli->inbuf) + 3;