summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/client/client.c153
-rw-r--r--source3/lib/system.c26
-rw-r--r--source3/libsmb/clifile.c131
-rw-r--r--source3/smbd/trans2.c26
4 files changed, 309 insertions, 27 deletions
diff --git a/source3/client/client.c b/source3/client/client.c
index e14bcaa261..42db009c58 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -1705,6 +1705,158 @@ static int cmd_chmod(void)
return 0;
}
+static const char *filetype_to_str(mode_t mode)
+{
+ if (S_ISREG(mode)) {
+ return "regular file";
+ } else if (S_ISDIR(mode)) {
+ return "directory";
+ } else
+#ifdef S_ISCHR
+ if (S_ISCHR(mode)) {
+ return "character device";
+ } else
+#endif
+#ifdef S_ISBLK
+ if (S_ISBLK(mode)) {
+ return "block device";
+ } else
+#endif
+#ifdef S_ISFIFO
+ if (S_ISFIFO(mode)) {
+ return "fifo";
+ } else
+#endif
+#ifdef S_ISLNK
+ if (S_ISLNK(mode)) {
+ return "symbolic link";
+ } else
+#endif
+#ifdef S_ISSOCK
+ if (S_ISSOCK(mode)) {
+ return "socket";
+ } else
+#endif
+ return "";
+}
+
+static char rwx_to_str(mode_t m, mode_t bt, char ret)
+{
+ if (m & bt) {
+ return ret;
+ } else {
+ return '-';
+ }
+}
+
+static char *unix_mode_to_str(char *s, mode_t m)
+{
+ char *p = s;
+ const char *str = filetype_to_str(m);
+
+ switch(str[0]) {
+ case 'd':
+ *p++ = 'd';
+ break;
+ case 'c':
+ *p++ = 'c';
+ break;
+ case 'b':
+ *p++ = 'b';
+ break;
+ case 'f':
+ *p++ = 'p';
+ break;
+ case 's':
+ *p++ = str[1] == 'y' ? 'l' : 's';
+ break;
+ case 'r':
+ default:
+ *p++ = '-';
+ break;
+ }
+ *p++ = rwx_to_str(m, S_IRUSR, 'r');
+ *p++ = rwx_to_str(m, S_IWUSR, 'w');
+ *p++ = rwx_to_str(m, S_IXUSR, 'x');
+ *p++ = rwx_to_str(m, S_IRGRP, 'r');
+ *p++ = rwx_to_str(m, S_IWGRP, 'w');
+ *p++ = rwx_to_str(m, S_IXGRP, 'x');
+ *p++ = rwx_to_str(m, S_IROTH, 'r');
+ *p++ = rwx_to_str(m, S_IWOTH, 'w');
+ *p++ = rwx_to_str(m, S_IXOTH, 'x');
+ *p++ = '\0';
+ return s;
+}
+
+/****************************************************************************
+ UNIX stat.
+****************************************************************************/
+
+static int cmd_stat(void)
+{
+ pstring src, name;
+ fstring mode_str;
+ SMB_STRUCT_STAT sbuf;
+
+ 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_nr(NULL,name,NULL,sizeof(name))) {
+ d_printf("stat file\n");
+ return 1;
+ }
+
+ pstrcat(src,name);
+
+ if (!cli_unix_stat(cli, src, &sbuf)) {
+ d_printf("%s stat file %s\n",
+ cli_errstr(cli), src);
+ return 1;
+ }
+
+ /* 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));
+
+#if defined(S_ISCHR) && defined(S_ISBLK)
+ if (S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_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));
+ } else
+#endif
+ d_printf("Inode: %.0f\tLinks: %u\n",
+ (double)sbuf.st_ino,
+ (unsigned int)sbuf.st_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);
+
+ strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_atime));
+ d_printf("Access: %s\n", mode_str);
+
+ strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_mtime));
+ d_printf("Modify: %s\n", mode_str);
+
+ strftime(mode_str, sizeof(mode_str), "%F %T %z", localtime(&sbuf.st_ctime));
+ d_printf("Change: %s\n", mode_str);
+
+ return 0;
+}
+
+
/****************************************************************************
UNIX chown.
****************************************************************************/
@@ -2234,6 +2386,7 @@ static struct
{"rm",cmd_del,"<mask> delete all matching files",{COMPL_REMOTE,COMPL_NONE}},
{"rmdir",cmd_rmdir,"<directory> remove a directory",{COMPL_NONE,COMPL_NONE}},
{"setmode",cmd_setmode,"filename <setmode string> change modes of file",{COMPL_REMOTE,COMPL_NONE}},
+ {"stat",cmd_stat,"filename Do a UNIX extensions stat call on a file",{COMPL_REMOTE,COMPL_REMOTE}},
{"symlink",cmd_symlink,"<oldname> <newname> create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}},
{"tar",cmd_tar,"tar <c|x>[IXFqbgNan] current directory to/from <file name>",{COMPL_NONE,COMPL_NONE}},
{"tarmode",cmd_tarmode,"<full|inc|reset|noreset> tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}},
diff --git a/source3/lib/system.c b/source3/lib/system.c
index a0007ec83c..b27ac5c00a 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -1580,3 +1580,29 @@ int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size
return -1;
#endif
}
+
+/****************************************************************************
+ Return the major devicenumber for UNIX extensions.
+****************************************************************************/
+
+uint32 unix_dev_major(SMB_DEV_T dev)
+{
+#if defined(HAVE_DEVICE_MAJOR_FN)
+ return (uint32)major(dev);
+#else
+ return (uint32)(dev >> 8);
+#endif
+}
+
+/****************************************************************************
+ Return the minor devicenumber for UNIX extensions.
+****************************************************************************/
+
+uint32 unix_dev_minor(SMB_DEV_T dev)
+{
+#if defined(HAVE_DEVICE_MINOR_FN)
+ return (uint32)minor(dev);
+#else
+ return (uint32)(dev & 0xff);
+#endif
+}
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index ff0edc6bb4..d302206949 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -77,7 +77,7 @@ static BOOL cli_link_internal(struct cli_state *cli, const char *oldname, const
Map standard UNIX permissions onto wire representations.
****************************************************************************/
-uint32 unix_perms_to_wire(mode_t perms)
+uint32 unix_perms_to_wire(mode_t perms)
{
unsigned int ret = 0;
@@ -103,6 +103,135 @@ uint32 unix_perms_to_wire(mode_t perms)
}
/****************************************************************************
+ Map wire permissions to standard UNIX.
+****************************************************************************/
+
+mode_t wire_perms_to_unix(uint32 perms)
+{
+ mode_t ret = (mode_t)0;
+
+ ret |= ((perms & UNIX_X_OTH) ? S_IXOTH : 0);
+ ret |= ((perms & UNIX_W_OTH) ? S_IWOTH : 0);
+ ret |= ((perms & UNIX_R_OTH) ? S_IROTH : 0);
+ ret |= ((perms & UNIX_X_GRP) ? S_IXGRP : 0);
+ ret |= ((perms & UNIX_W_GRP) ? S_IWGRP : 0);
+ ret |= ((perms & UNIX_R_GRP) ? S_IRGRP : 0);
+ ret |= ((perms & UNIX_X_USR) ? S_IXUSR : 0);
+ ret |= ((perms & UNIX_W_USR) ? S_IWUSR : 0);
+ ret |= ((perms & UNIX_R_USR) ? S_IRUSR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & UNIX_STICKY) ? S_ISVTX : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & UNIX_SET_GID) ? S_ISGID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & UNIX_SET_UID) ? S_ISUID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Return the file type from the wire filetype for UNIX extensions.
+****************************************************************************/
+
+static mode_t unix_filetype_from_wire(uint32 wire_type)
+{
+ switch (wire_type) {
+ case UNIX_TYPE_FILE:
+ return S_IFREG;
+ case UNIX_TYPE_DIR:
+ return S_IFDIR;
+#ifdef S_IFLNK
+ case UNIX_TYPE_SYMLINK:
+ return S_IFLNK;
+#endif
+#ifdef S_IFCHR
+ case UNIX_TYPE_CHARDEV:
+ return S_IFCHR;
+#endif
+#ifdef S_IFBLK
+ case UNIX_TYPE_BLKDEV:
+ return S_IFBLK;
+#endif
+#ifdef S_IFIFO
+ case UNIX_TYPE_FIFO:
+ return S_IFIFO;
+#endif
+#ifdef S_IFSOCK
+ case UNIX_TYPE_SOCKET:
+ return S_IFSOCK;
+#endif
+ default:
+ return (mode_t)0;
+ }
+}
+
+/****************************************************************************
+ Stat a file (UNIX extensions).
+****************************************************************************/
+
+BOOL cli_unix_stat(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf)
+{
+ unsigned int param_len = 0;
+ unsigned int data_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char param[sizeof(pstring)+6];
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+
+ ZERO_STRUCTP(sbuf);
+
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_QUERY_FILE_UNIX_BASIC);
+ p += 6;
+ p += clistr_push(cli, p, name, sizeof(pstring)-6, STR_TERMINATE);
+ param_len = PTR_DIFF(p, param);
+
+ 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 */
+ NULL, 0, cli->max_xmit /* data, length, max */
+ )) {
+ return False;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return False;
+ }
+
+ sbuf->st_size = IVAL2_TO_SMB_BIG_UINT(rdata,0); /* total size, in bytes */
+ sbuf->st_blocks = IVAL2_TO_SMB_BIG_UINT(rdata,8); /* number of blocks allocated */
+ sbuf->st_blocks /= STAT_ST_BLOCKSIZE;
+ sbuf->st_ctime = interpret_long_date(rdata + 16); /* time of last change */
+ sbuf->st_atime = interpret_long_date(rdata + 24); /* time of last access */
+ sbuf->st_mtime = interpret_long_date(rdata + 32); /* time of last modification */
+ sbuf->st_uid = IVAL(rdata,40); /* user ID of owner */
+ sbuf->st_gid = IVAL(rdata,48); /* group ID of owner */
+ sbuf->st_mode |= unix_filetype_from_wire(IVAL(rdata, 56));
+#if defined(HAVE_MAKEDEV)
+ {
+ uint32 dev_major = IVAL(rdata,60);
+ uint32 dev_minor = IVAL(rdata,68);
+ sbuf->st_rdev = makedev(dev_major, dev_minor);
+ }
+#endif
+ sbuf->st_ino = (SMB_INO_T)IVAL2_TO_SMB_BIG_UINT(rdata,76); /* inode */
+ sbuf->st_mode |= wire_perms_to_unix(IVAL(rdata,84)); /* protection */
+ sbuf->st_nlink = IVAL(rdata,92); /* number of hard links */
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ return True;
+}
+
+/****************************************************************************
Symlink a file (UNIX extensions).
****************************************************************************/
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index a7bc2efb4a..825481984d 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -757,32 +757,6 @@ static uint32 unix_filetype(mode_t mode)
}
/****************************************************************************
- Return the major devicenumber for UNIX extensions.
-****************************************************************************/
-
-static uint32 unix_dev_major(SMB_DEV_T dev)
-{
-#if defined(HAVE_DEVICE_MAJOR_FN)
- return (uint32)major(dev);
-#else
- return (uint32)(dev >> 8);
-#endif
-}
-
-/****************************************************************************
- Return the minor devicenumber for UNIX extensions.
-****************************************************************************/
-
-static uint32 unix_dev_minor(SMB_DEV_T dev)
-{
-#if defined(HAVE_DEVICE_MINOR_FN)
- return (uint32)minor(dev);
-#else
- return (uint32)(dev & 0xff);
-#endif
-}
-
-/****************************************************************************
Map wire perms onto standard UNIX permissions. Obey share restrictions.
****************************************************************************/