r2651: Added 'stat' command to smbclient to exercise the UNIX_FILE_BASIC
authorJeremy Allison <jra@samba.org>
Sun, 26 Sep 2004 06:27:54 +0000 (06:27 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:52:48 +0000 (10:52 -0500)
info level. Outputs data on the file in the same format the the
stat command in Linux. Should be useful to people wanting to learn
how to parse the UNIX extension output.
Yes I will add the docs later :-).
Jeremy.

source/client/client.c
source/lib/system.c
source/libsmb/clifile.c
source/smbd/trans2.c

index e14bcaa261653af0ce379cc407ab383f1d04e4b1..42db009c58a69eba6840832c9c93bd67b11178a1 100644 (file)
@@ -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}},
index a0007ec83cd277fc966e14fcacbfc4c64ab3ef9e..b27ac5c00ad51cc31a2cc1075302ca13ea4960f4 100644 (file)
@@ -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
+}
index ff0edc6bb4e40c1dcee02cddcdf197b53f773105..d3022069491d99ec8333987759c19d432133bee6 100644 (file)
@@ -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;
 
@@ -102,6 +102,135 @@ uint32  unix_perms_to_wire(mode_t perms)
         return ret;
 }
 
+/****************************************************************************
+ 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).
 ****************************************************************************/
index a7bc2efb4aff3e6ea2bfd2719a96756c7a21d6d1..825481984d8ff9e97be9334d849a269f3e510788 100644 (file)
@@ -756,32 +756,6 @@ static uint32 unix_filetype(mode_t mode)
        return UNIX_TYPE_UNKNOWN;
 }
 
-/****************************************************************************
- 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.
 ****************************************************************************/