From 0173911b46412b520e37b090cf65382f2f5fca38 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 16 Jan 2002 20:13:28 +0000 Subject: Added CIFS UNIX extension code to client. Jeremy. (This used to be commit 794c3e2c76aae57d054e46b185def104ca02977c) --- source3/client/client.c | 146 ++++++++++++++++++++++++++++++++++++++ source3/include/smb_macros.h | 6 ++ source3/libsmb/clifile.c | 164 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 316 insertions(+) diff --git a/source3/client/client.c b/source3/client/client.c index 61a123b9e5..70f39902fc 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -1558,6 +1558,148 @@ static int cmd_rmdir(void) return 0; } +/**************************************************************************** + UNIX hardlink. +****************************************************************************/ + +static int cmd_link(void) +{ + pstring src,dest; + fstring buf,buf2; + + if (!SERVER_HAS_UNIX_CIFS(cli)) { + d_printf("Server doesn't support UNIX CIFS calls.\n"); + return 1; + } + + pstrcpy(src,cur_dir); + pstrcpy(dest,cur_dir); + + if (!next_token(NULL,buf,NULL,sizeof(buf)) || + !next_token(NULL,buf2,NULL, sizeof(buf2))) { + d_printf("link \n"); + return 1; + } + + pstrcat(src,buf); + pstrcat(dest,buf2); + + if (!cli_unix_hardlink(cli, src, dest)) { + d_printf("%s linking files (%s -> %s)\n", cli_errstr(cli), src, dest); + return 1; + } + + return 0; +} + +/**************************************************************************** + UNIX symlink. +****************************************************************************/ + +static int cmd_symlink(void) +{ + pstring src,dest; + fstring buf,buf2; + + if (!SERVER_HAS_UNIX_CIFS(cli)) { + d_printf("Server doesn't support UNIX CIFS calls.\n"); + return 1; + } + + pstrcpy(src,cur_dir); + pstrcpy(dest,cur_dir); + + if (!next_token(NULL,buf,NULL,sizeof(buf)) || + !next_token(NULL,buf2,NULL, sizeof(buf2))) { + d_printf("symlink \n"); + return 1; + } + + pstrcat(src,buf); + pstrcat(dest,buf2); + + if (!cli_unix_symlink(cli, src, dest)) { + d_printf("%s symlinking files (%s -> %s)\n", + cli_errstr(cli), src, dest); + return 1; + } + + return 0; +} + +/**************************************************************************** + UNIX chmod. +****************************************************************************/ + +static int cmd_chmod(void) +{ + pstring src; + mode_t mode; + fstring buf, buf2; + + if (!SERVER_HAS_UNIX_CIFS(cli)) { + d_printf("Server doesn't support UNIX CIFS calls.\n"); + return 1; + } + + pstrcpy(src,cur_dir); + + if (!next_token(NULL,buf,NULL,sizeof(buf)) || + !next_token(NULL,buf2,NULL, sizeof(buf2))) { + d_printf("chmod mode file\n"); + return 1; + } + + mode = (mode_t)strtol(buf, NULL, 8); + pstrcat(src,buf2); + + if (!cli_unix_chmod(cli, src, mode)) { + d_printf("%s chmod file %s 0%o\n", + cli_errstr(cli), src, (unsigned int)mode); + return 1; + } + + return 0; +} + +/**************************************************************************** + UNIX chown. +****************************************************************************/ + +static int cmd_chown(void) +{ + pstring src; + uid_t uid; + gid_t gid; + fstring buf, buf2, buf3; + + if (!SERVER_HAS_UNIX_CIFS(cli)) { + d_printf("Server doesn't support UNIX CIFS calls.\n"); + return 1; + } + + pstrcpy(src,cur_dir); + + if (!next_token(NULL,buf,NULL,sizeof(buf)) || + !next_token(NULL,buf2,NULL, sizeof(buf2)) || + !next_token(NULL,buf3,NULL, sizeof(buf3))) { + d_printf("chown uid gid file\n"); + return 1; + } + + uid = (uid_t)atoi(buf); + gid = (gid_t)atoi(buf2); + pstrcat(src,buf3); + + if (!cli_unix_chown(cli, src, uid, gid)) { + d_printf("%s chown file %s uid=%d, gid=%d\n", + cli_errstr(cli), src, (int)uid, (int)gid); + return 1; + } + + return 0; +} + /**************************************************************************** rename some files ****************************************************************************/ @@ -1826,6 +1968,8 @@ struct {"blocksize",cmd_block,"blocksize (default 20)",{COMPL_NONE,COMPL_NONE}}, {"cancel",cmd_cancel," cancel a print queue entry",{COMPL_NONE,COMPL_NONE}}, {"cd",cmd_cd,"[directory] change/report the remote directory",{COMPL_REMOTE,COMPL_NONE}}, + {"chmod",cmd_chmod," chmod a file using UNIX permission",{COMPL_REMOTE,COMPL_REMOTE}}, + {"chown",cmd_chown," chown a file using UNIX uids and gids",{COMPL_REMOTE,COMPL_REMOTE}}, {"del",cmd_del," delete all matching files",{COMPL_REMOTE,COMPL_NONE}}, {"dir",cmd_dir," list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}}, {"du",cmd_du," computes the total size of the current directory",{COMPL_REMOTE,COMPL_NONE}}, @@ -1834,6 +1978,7 @@ struct {"help",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}}, {"history",cmd_history,"displays the command history",{COMPL_NONE,COMPL_NONE}}, {"lcd",cmd_lcd,"[directory] change/report the local current working directory",{COMPL_LOCAL,COMPL_NONE}}, + {"link",cmd_link," create a UNIX hard link",{COMPL_REMOTE,COMPL_REMOTE}}, {"lowercase",cmd_lowercase,"toggle lowercasing of filenames for get",{COMPL_NONE,COMPL_NONE}}, {"ls",cmd_dir," list the contents of the current directory",{COMPL_REMOTE,COMPL_NONE}}, {"mask",cmd_select," mask all filenames against this",{COMPL_REMOTE,COMPL_NONE}}, @@ -1858,6 +2003,7 @@ struct {"rm",cmd_del," delete all matching files",{COMPL_REMOTE,COMPL_NONE}}, {"rmdir",cmd_rmdir," remove a directory",{COMPL_NONE,COMPL_NONE}}, {"setmode",cmd_setmode,"filename change modes of file",{COMPL_REMOTE,COMPL_NONE}}, + {"symlink",cmd_symlink," create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}}, {"tar",cmd_tar,"tar [IXFqbgNan] current directory to/from ",{COMPL_NONE,COMPL_NONE}}, {"tarmode",cmd_tarmode," tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}}, {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}}, diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index 83ee12936c..15a10f0104 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -219,6 +219,12 @@ copy an IP address from one buffer to another #define putip(dest,src) memcpy(dest,src,4) +/******************************************************************* + Return True if a server has CIFS UNIX capabilities. +********************************************************************/ + +#define SERVER_HAS_UNIX_CIFS(c) ((c)->capabilities & CAP_UNIX) + /**************************************************************************** Make a filename into unix format. ****************************************************************************/ diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 7cd1e4ddb1..e282c9a6ab 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3,6 +3,7 @@ Version 3.0 client file operations Copyright (C) Andrew Tridgell 1994-1998 + Copyright (C) Jeremy Allison 2001-2002 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 @@ -23,6 +24,169 @@ #include "includes.h" +/**************************************************************************** + Hard/Symlink a file (UNIX extensions). +****************************************************************************/ + +static BOOL cli_link_internal(struct cli_state *cli, const char *fname_src, const char *fname_dst, BOOL hard_link) +{ + int data_len = 0; + int param_len = 0; + uint16 setup = TRANSACT2_SETPATHINFO; + char param[sizeof(pstring)+6]; + pstring data; + char *rparam=NULL, *rdata=NULL; + char *p; + + memset(param, 0, sizeof(param)); + SSVAL(param,0,hard_link ? SMB_SET_FILE_UNIX_HLINK : SMB_SET_FILE_UNIX_LINK); + p = ¶m[6]; + + p += clistr_push(cli, p, fname_src, -1, STR_TERMINATE); + param_len = PTR_DIFF(p, param); + + p = data; + p += clistr_push(cli, p, fname_dst, -1, STR_TERMINATE); + data_len = PTR_DIFF(p, data); + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + (char *)&data, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + return True; +} + +/**************************************************************************** + Map standard UNIX permissions onto wire representations. +****************************************************************************/ + +uint32 unix_perms_to_wire(mode_t perms) +{ + uint ret = 0; + + ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0); + ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0); + ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0); + ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0); + ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0); + ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0); + ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0); + ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0); + ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0); +#ifdef S_ISVTX + ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0); +#endif +#ifdef S_ISGID + ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0); +#endif +#ifdef S_ISUID + ret |= ((perms & S_ISVTX) ? UNIX_SET_UID : 0); +#endif + return ret; +} + +/**************************************************************************** + Symlink a file (UNIX extensions). +****************************************************************************/ + +BOOL cli_unix_symlink(struct cli_state *cli, const char *fname_src, const char *fname_dst) +{ + return cli_link_internal(cli, fname_src, fname_dst, False); +} + +/**************************************************************************** + Hard a file (UNIX extensions). +****************************************************************************/ + +BOOL cli_unix_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst) +{ + return cli_link_internal(cli, fname_src, fname_dst, True); +} + +/**************************************************************************** + Chmod or chown a file internal (UNIX extensions). +****************************************************************************/ + +static BOOL cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname, uint32 mode, uint32 uid, uint32 gid) +{ + int data_len = 0; + int param_len = 0; + uint16 setup = TRANSACT2_SETPATHINFO; + char param[sizeof(pstring)+6]; + char data[100]; + char *rparam=NULL, *rdata=NULL; + char *p; + + memset(param, 0, sizeof(param)); + memset(data, 0, sizeof(data)); + SSVAL(param,0,SMB_SET_FILE_UNIX_BASIC); + p = ¶m[6]; + + p += clistr_push(cli, p, fname, -1, STR_TERMINATE); + param_len = PTR_DIFF(p, param); + + SIVAL(data,40,uid); + SIVAL(data,48,gid); + SIVAL(data,84,mode); + + data_len = 100; + + if (!cli_send_trans(cli, SMBtrans2, + NULL, /* name */ + -1, 0, /* fid, flags */ + &setup, 1, 0, /* setup, length, max */ + param, param_len, 2, /* param, length, max */ + (char *)&data, data_len, cli->max_xmit /* data, length, max */ + )) { + return False; + } + + if (!cli_receive_trans(cli, SMBtrans2, + &rparam, ¶m_len, + &rdata, &data_len)) { + return False; + } + + SAFE_FREE(rdata); + SAFE_FREE(rparam); + + return True; +} + +/**************************************************************************** + chmod a file (UNIX extensions). +****************************************************************************/ + +BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode) +{ + return cli_unix_chmod_chown_internal(cli, fname, + unix_perms_to_wire(mode), UID_NO_CHANGE, GID_NO_CHANGE); +} + +/**************************************************************************** + chown a file (UNIX extensions). +****************************************************************************/ + +BOOL cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid) +{ + return cli_unix_chmod_chown_internal(cli, fname, MODE_NO_CHANGE, (uint32)uid, (uint32)gid); +} + /**************************************************************************** Rename a file. ****************************************************************************/ -- cgit