Add a smbclient "readlink" command and add docs for it.
[ira/wip.git] / source3 / client / client.c
index 0271b456c3b8dc00f1fa4ee7f6d8ec0b2f045f10..2edeb1ae2b26bd32c78174bc34459f55bcd0e537 100644 (file)
@@ -535,12 +535,12 @@ static void display_finfo(file_info *finfo, const char *dir)
                dir_total += finfo->size;
        } else {
                char *afname = NULL;
-               int fnum;
+               uint16_t fnum;
 
                /* skip if this is . or .. */
                if ( strequal(finfo->name,"..") || strequal(finfo->name,".") )
                        return;
-               /* create absolute filename for cli_nt_create() FIXME */
+               /* create absolute filename for cli_ntcreate() FIXME */
                afname = talloc_asprintf(ctx,
                                        "%s%s%s",
                                        dir,
@@ -554,8 +554,9 @@ static void display_finfo(file_info *finfo, const char *dir)
                d_printf( "MODE:%s\n", attrib_string(finfo->mode));
                d_printf( "SIZE:%.0f\n", (double)finfo->size);
                d_printf( "MTIME:%s", time_to_asc(t));
-               fnum = cli_nt_create(finfo->cli, afname, CREATE_ACCESS_READ);
-               if (fnum == -1) {
+               if (!NT_STATUS_IS_OK(cli_ntcreate(finfo->cli, afname, 0,
+                               CREATE_ACCESS_READ, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                               FILE_OPEN, 0x0, 0x0, &fnum))) {
                        DEBUG( 0, ("display_finfo() Failed to open %s: %s\n",
                                afname,
                                cli_errstr( finfo->cli)));
@@ -999,7 +1000,8 @@ static NTSTATUS writefile_sink(char *buf, size_t n, void *priv)
 static int do_get(const char *rname, const char *lname_in, bool reget)
 {
        TALLOC_CTX *ctx = talloc_tos();
-       int handle = 0, fnum;
+       int handle = 0;
+       uint16_t fnum;
        bool newhandle = false;
        struct timeval tp_start;
        uint16 attr;
@@ -1028,9 +1030,7 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
 
        GetTimeOfDay(&tp_start);
 
-       fnum = cli_open(targetcli, targetname, O_RDONLY, DENY_NONE);
-
-       if (fnum == -1) {
+       if (!NT_STATUS_IS_OK(cli_open(targetcli, targetname, O_RDONLY, DENY_NONE, &fnum))) {
                d_printf("%s opening remote file %s\n",cli_errstr(cli),rname);
                return 1;
        }
@@ -1060,8 +1060,8 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
 
        if (!cli_qfileinfo(targetcli, fnum,
                           &attr, &size, NULL, NULL, NULL, NULL, NULL) &&
-           !cli_getattrE(targetcli, fnum,
-                         &attr, &size, NULL, NULL, NULL)) {
+           !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum,
+                         &attr, &size, NULL, NULL, NULL))) {
                d_printf("getattrib: %s\n",cli_errstr(targetcli));
                return 1;
        }
@@ -1078,7 +1078,7 @@ static int do_get(const char *rname, const char *lname_in, bool reget)
                return 1;
        }
 
-       if (!cli_close(targetcli, fnum)) {
+       if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
                d_printf("Error %s closing remote file\n",cli_errstr(cli));
                rc = 1;
        }
@@ -1618,7 +1618,7 @@ static int cmd_allinfo(void)
 static int do_put(const char *rname, const char *lname, bool reput)
 {
        TALLOC_CTX *ctx = talloc_tos();
-       int fnum;
+       uint16_t fnum;
        XFILE *f;
        SMB_OFF_T start = 0;
        int rc = 0;
@@ -1636,19 +1636,19 @@ static int do_put(const char *rname, const char *lname, bool reput)
        GetTimeOfDay(&tp_start);
 
        if (reput) {
-               fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE);
-               if (fnum >= 0) {
+               status = cli_open(targetcli, targetname, O_RDWR|O_CREAT, DENY_NONE, &fnum);
+               if (NT_STATUS_IS_OK(status)) {
                        if (!cli_qfileinfo(targetcli, fnum, NULL, &start, NULL, NULL, NULL, NULL, NULL) &&
-                           !cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL)) {
+                           !NT_STATUS_IS_OK(cli_getattrE(targetcli, fnum, NULL, &start, NULL, NULL, NULL))) {
                                d_printf("getattrib: %s\n",cli_errstr(cli));
                                return 1;
                        }
                }
        } else {
-               fnum = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE);
+               status = cli_open(targetcli, targetname, O_RDWR|O_CREAT|O_TRUNC, DENY_NONE, &fnum);
        }
 
-       if (fnum == -1) {
+       if (!NT_STATUS_IS_OK(status)) {
                d_printf("%s opening remote file %s\n",cli_errstr(targetcli),rname);
                return 1;
        }
@@ -1690,7 +1690,7 @@ static int do_put(const char *rname, const char *lname, bool reput)
                d_fprintf(stderr, "cli_push returned %s\n", nt_errstr(status));
        }
 
-       if (!cli_close(targetcli, fnum)) {
+       if (!NT_STATUS_IS_OK(cli_close(targetcli, fnum))) {
                d_printf("%s closing remote file %s\n",cli_errstr(cli),rname);
                x_fclose(f);
                return 1;
@@ -2115,7 +2115,7 @@ static void do_del(file_info *finfo, const char *dir)
                return;
        }
 
-       if (!cli_unlink(finfo->cli, mask)) {
+       if (!NT_STATUS_IS_OK(cli_unlink(finfo->cli, mask, aSYSTEM | aHIDDEN))) {
                d_printf("%s deleting remote file %s\n",
                                cli_errstr(finfo->cli),mask);
        }
@@ -2191,7 +2191,7 @@ static int cmd_wdel(void)
                return 1;
        }
 
-       if (!cli_unlink_full(targetcli, targetname, attribute)) {
+       if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetname, attribute))) {
                d_printf("%s deleting remote files %s\n",cli_errstr(targetcli),targetname);
        }
        return 0;
@@ -2207,7 +2207,7 @@ static int cmd_open(void)
        char *buf = NULL;
        char *targetname = NULL;
        struct cli_state *targetcli;
-       int fnum;
+       uint16_t fnum = (uint16_t)-1;
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                d_printf("open <filename>\n");
@@ -2226,10 +2226,12 @@ static int cmd_open(void)
                return 1;
        }
 
-       fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA|FILE_WRITE_DATA);
-       if (fnum == -1) {
-               fnum = cli_nt_create(targetcli, targetname, FILE_READ_DATA);
-               if (fnum != -1) {
+       if (!NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
+                       FILE_READ_DATA|FILE_WRITE_DATA, 0,
+                       FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
+               if (NT_STATUS_IS_OK(cli_ntcreate(targetcli, targetname, 0,
+                               FILE_READ_DATA, 0,
+                               FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0x0, 0x0, &fnum))) {
                        d_printf("open file %s: for read/write fnum %d\n", targetname, fnum);
                } else {
                        d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
@@ -2294,7 +2296,7 @@ static int cmd_posix_open(void)
        char *targetname = NULL;
        struct cli_state *targetcli;
        mode_t mode;
-       int fnum;
+       uint16_t fnum;
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                d_printf("posix_open <filename> 0<mode>\n");
@@ -2319,10 +2321,8 @@ static int cmd_posix_open(void)
                return 1;
        }
 
-       fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode);
-       if (fnum == -1) {
-               fnum = cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode);
-               if (fnum != -1) {
+       if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDWR, mode, &fnum))) {
+               if (!NT_STATUS_IS_OK(cli_posix_open(targetcli, targetname, O_CREAT|O_RDONLY, mode, &fnum))) {
                        d_printf("posix_open file %s: for read/write fnum %d\n", targetname, fnum);
                } else {
                        d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
@@ -2342,7 +2342,6 @@ static int cmd_posix_mkdir(void)
        char *targetname = NULL;
        struct cli_state *targetcli;
        mode_t mode;
-       int fnum;
 
        if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
                d_printf("posix_mkdir <filename> 0<mode>\n");
@@ -2367,8 +2366,7 @@ static int cmd_posix_mkdir(void)
                return 1;
        }
 
-       fnum = cli_posix_mkdir(targetcli, targetname, mode);
-       if (fnum == -1) {
+       if (!NT_STATUS_IS_OK(cli_posix_mkdir(targetcli, targetname, mode))) {
                d_printf("Failed to open file %s. %s\n", targetname, cli_errstr(cli));
        } else {
                d_printf("posix_mkdir created directory %s\n", targetname);
@@ -2457,7 +2455,7 @@ static int cmd_close(void)
 
        fnum = atoi(buf);
        /* We really should use the targetcli here.... */
-       if (!cli_close(cli, fnum)) {
+       if (!NT_STATUS_IS_OK(cli_close(cli, fnum))) {
                d_printf("close %d: %s\n", fnum, cli_errstr(cli));
                return 1;
        }
@@ -2727,13 +2725,61 @@ static int cmd_link(void)
                return 1;
        }
 
-       if (!cli_unix_hardlink(targetcli, targetname, newname)) {
+       if (!NT_STATUS_IS_OK(cli_posix_hardlink(targetcli, targetname, newname))) {
                d_printf("%s linking files (%s -> %s)\n", cli_errstr(targetcli), newname, oldname);
                return 1;
        }
        return 0;
 }
 
+/****************************************************************************
+ UNIX readlink.
+****************************************************************************/
+
+static int cmd_readlink(void)
+{
+       TALLOC_CTX *ctx = talloc_tos();
+       char *name= NULL;
+       char *buf = NULL;
+       char *targetname = NULL;
+       char linkname[PATH_MAX+1];
+       struct cli_state *targetcli;
+
+       if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) {
+               d_printf("readlink <name>\n");
+               return 1;
+       }
+       name = talloc_asprintf(ctx,
+                       "%s%s",
+                       client_get_cur_dir(),
+                       buf);
+       if (!name) {
+               return 1;
+       }
+
+       if (!cli_resolve_path(ctx, "", auth_info, cli, name, &targetcli, &targetname)) {
+               d_printf("readlink %s: %s\n", name, cli_errstr(cli));
+               return 1;
+       }
+
+       if (!SERVER_HAS_UNIX_CIFS(targetcli)) {
+               d_printf("Server doesn't support UNIX CIFS calls.\n");
+               return 1;
+       }
+
+       if (!NT_STATUS_IS_OK(cli_posix_readlink(targetcli, name,
+                       linkname, PATH_MAX+1))) {
+               d_printf("%s readlink on file %s\n",
+                       cli_errstr(targetcli), name);
+               return 1;
+       }
+
+       d_printf("%s -> %s\n", name, linkname);
+
+       return 0;
+}
+
+
 /****************************************************************************
  UNIX symlink.
 ****************************************************************************/
@@ -2778,7 +2824,7 @@ static int cmd_symlink(void)
                return 1;
        }
 
-       if (!cli_unix_symlink(targetcli, targetname, newname)) {
+       if (!NT_STATUS_IS_OK(cli_posix_symlink(targetcli, targetname, newname))) {
                d_printf("%s symlinking files (%s -> %s)\n",
                        cli_errstr(targetcli), newname, targetname);
                return 1;
@@ -3024,7 +3070,7 @@ static int cmd_getfacl(void)
        }
 
        d_printf("# file: %s\n", src);
-       d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_uid, (unsigned int)sbuf.st_gid);
+       d_printf("# owner: %u\n# group: %u\n", (unsigned int)sbuf.st_ex_uid, (unsigned int)sbuf.st_ex_gid);
 
        if (num_file_acls == 0 && num_dir_acls == 0) {
                d_printf("No acls found.\n");
@@ -3122,6 +3168,7 @@ static int cmd_stat(void)
        fstring mode_str;
        SMB_STRUCT_STAT sbuf;
        struct tm *lt;
+       time_t tmp_time;
 
        if (!next_token_talloc(ctx, &cmd_ptr,&name,NULL)) {
                d_printf("stat file\n");
@@ -3154,30 +3201,31 @@ static int cmd_stat(void)
        /* Print out the stat values. */
        d_printf("File: %s\n", src);
        d_printf("Size: %-12.0f\tBlocks: %u\t%s\n",
-               (double)sbuf.st_size,
-               (unsigned int)sbuf.st_blocks,
-               filetype_to_str(sbuf.st_mode));
+               (double)sbuf.st_ex_size,
+               (unsigned int)sbuf.st_ex_blocks,
+               filetype_to_str(sbuf.st_ex_mode));
 
 #if defined(S_ISCHR) && defined(S_ISBLK)
-       if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode)) {
+       if (S_ISCHR(sbuf.st_ex_mode) || S_ISBLK(sbuf.st_ex_mode)) {
                d_printf("Inode: %.0f\tLinks: %u\tDevice type: %u,%u\n",
-                       (double)sbuf.st_ino,
-                       (unsigned int)sbuf.st_nlink,
-                       unix_dev_major(sbuf.st_rdev),
-                       unix_dev_minor(sbuf.st_rdev));
+                       (double)sbuf.st_ex_ino,
+                       (unsigned int)sbuf.st_ex_nlink,
+                       unix_dev_major(sbuf.st_ex_rdev),
+                       unix_dev_minor(sbuf.st_ex_rdev));
        } else
 #endif
                d_printf("Inode: %.0f\tLinks: %u\n",
-                       (double)sbuf.st_ino,
-                       (unsigned int)sbuf.st_nlink);
+                       (double)sbuf.st_ex_ino,
+                       (unsigned int)sbuf.st_ex_nlink);
 
        d_printf("Access: (0%03o/%s)\tUid: %u\tGid: %u\n",
-               ((int)sbuf.st_mode & 0777),
-               unix_mode_to_str(mode_str, sbuf.st_mode),
-               (unsigned int)sbuf.st_uid,
-               (unsigned int)sbuf.st_gid);
+               ((int)sbuf.st_ex_mode & 0777),
+               unix_mode_to_str(mode_str, sbuf.st_ex_mode),
+               (unsigned int)sbuf.st_ex_uid,
+               (unsigned int)sbuf.st_ex_gid);
 
-       lt = localtime(&sbuf.st_atime);
+       tmp_time = convert_timespec_to_time_t(sbuf.st_ex_atime);
+       lt = localtime(&tmp_time);
        if (lt) {
                strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
        } else {
@@ -3185,7 +3233,8 @@ static int cmd_stat(void)
        }
        d_printf("Access: %s\n", mode_str);
 
-       lt = localtime(&sbuf.st_mtime);
+       tmp_time = convert_timespec_to_time_t(sbuf.st_ex_mtime);
+       lt = localtime(&tmp_time);
        if (lt) {
                strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
        } else {
@@ -3193,7 +3242,8 @@ static int cmd_stat(void)
        }
        d_printf("Modify: %s\n", mode_str);
 
-       lt = localtime(&sbuf.st_ctime);
+       tmp_time = convert_timespec_to_time_t(sbuf.st_ex_ctime);
+       lt = localtime(&tmp_time);
        if (lt) {
                strftime(mode_str, sizeof(mode_str), "%Y-%m-%d %T %z", lt);
        } else {
@@ -3402,7 +3452,7 @@ static int cmd_newer(void)
 
        ok = next_token_talloc(ctx, &cmd_ptr,&buf,NULL);
        if (ok && (sys_stat(buf,&sbuf) == 0)) {
-               newer_than = sbuf.st_mtime;
+               newer_than = convert_timespec_to_time_t(sbuf.st_ex_mtime);
                DEBUG(1,("Getting files newer than %s",
                         time_to_asc(newer_than)));
        } else {
@@ -3951,6 +4001,7 @@ static struct {
   {"q",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
   {"queue",cmd_queue,"show the print queue",{COMPL_NONE,COMPL_NONE}},
   {"quit",cmd_quit,"logoff the server",{COMPL_NONE,COMPL_NONE}},
+  {"readlink",cmd_readlink,"filename Do a UNIX extensions readlink call on a symlink",{COMPL_REMOTE,COMPL_REMOTE}},
   {"rd",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
   {"recurse",cmd_recurse,"toggle directory recursion for mget and mput",{COMPL_NONE,COMPL_NONE}},  
   {"reget",cmd_reget,"<remote name> [local name] get a file restarting at end of local file",{COMPL_REMOTE,COMPL_LOCAL}},
@@ -4551,8 +4602,6 @@ static int process(const char *base_directory)
 
 static int do_host_query(const char *query_host)
 {
-       struct sockaddr_storage ss;
-
        cli = cli_cm_open(talloc_tos(), NULL,
                        query_host, "IPC$", auth_info, true, smb_encrypt,
                        max_protocol, port, name_type);
@@ -4561,10 +4610,16 @@ static int do_host_query(const char *query_host)
 
        browse_host(true);
 
-       if (interpret_string_addr(&ss, query_host, 0) && (ss.ss_family != AF_INET)) {
-               d_printf("%s is an IPv6 address -- no workgroup available\n",
-                       query_host);
-               return 1;
+       /* Ensure that the host can do IPv4 */
+
+       if (!interpret_addr(query_host)) {
+               struct sockaddr_storage ss;
+               if (interpret_string_addr(&ss, query_host, 0) &&
+                               (ss.ss_family != AF_INET)) {
+                       d_printf("%s is an IPv6 address -- no workgroup available\n",
+                               query_host);
+                       return 1;
+               }
        }
 
        if (port != 139) {