diff mbox series

smbinfo: Add more File*Information classes

Message ID 20190129065357.3935-2-lsahlber@redhat.com (mailing list archive)
State New, archived
Headers show
Series smbinfo: Add more File*Information classes | expand

Commit Message

Ronnie Sahlberg Jan. 29, 2019, 6:53 a.m. UTC
Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
---
 smbinfo.c   | 483 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 smbinfo.rst |  34 ++++-
 2 files changed, 497 insertions(+), 20 deletions(-)

Comments

Steve French Jan. 29, 2019, 1:10 p.m. UTC | #1
An additional minor patch to add help text for the most important of
the newly added info classes (fileallinfo).

See attached.

Also (minor/trivial point) note that in Ronnie's patch, there is a
little bit of extra whitespace.

On Tue, Jan 29, 2019 at 12:54 AM Ronnie Sahlberg <lsahlber@redhat.com> wrote:
>
> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
> ---
>  smbinfo.c   | 483 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  smbinfo.rst |  34 ++++-
>  2 files changed, 497 insertions(+), 20 deletions(-)
>
> diff --git a/smbinfo.c b/smbinfo.c
> index b1c129b..de9ebf6 100644
> --- a/smbinfo.c
> +++ b/smbinfo.c
> @@ -66,6 +66,447 @@ usage(char *name)
>  }
>
>  static void
> +win_to_timeval(uint64_t smb2_time, struct timeval *tv)
> +{
> +  tv->tv_usec = (smb2_time / 10) % 1000000;
> +  tv->tv_sec  = (smb2_time - 116444736000000000) / 10000000;
> +}
> +
> +struct bit_string {
> +        unsigned int bit;
> +        char *string;
> +};
> +
> +struct bit_string directory_access_mask[] = {
> +        { 0x00000001, "LIST_DIRECTORY" },
> +        { 0x00000002, "ADD_FILE" },
> +        { 0x00000004, "ADD_SUBDIRECTORY" },
> +        { 0x00000008, "READ_EA" },
> +        { 0x00000010, "WRITE_EA" },
> +        { 0x00000020, "TRAVERSE" },
> +        { 0x00000040, "DELETE_CHILD" },
> +        { 0x00000080, "READ_ATTRIBUTES" },
> +        { 0x00000100, "WRITE_ATTRIBUTES" },
> +        { 0x00010000, "DELETE" },
> +        { 0x00020000, "READ_CONTROL" },
> +        { 0x00040000, "WRITE_DAC" },
> +        { 0x00080000, "WRITE_OWNER" },
> +        { 0x00100000, "SYNCHRONIZER" },
> +        { 0x01000000, "ACCESS_SYSTEM_SECURITY" },
> +        { 0x02000000, "MAXIMUM_ALLOWED" },
> +        { 0x10000000, "GENERIC_ALL" },
> +        { 0x20000000, "GENERIC_EXECUTE" },
> +        { 0x40000000, "GENERIC_WRITE" },
> +        { 0x80000000, "GENERIC_READ" },
> +        { 0, NULL }
> +};
> +
> +struct bit_string file_access_mask[] = {
> +        { 0x00000001, "READ_DATA" },
> +        { 0x00000002, "WRITE_DATA" },
> +        { 0x00000004, "APPEND_DATA" },
> +        { 0x00000008, "READ_EA" },
> +        { 0x00000010, "WRITE_EA" },
> +        { 0x00000020, "EXECUTE" },
> +        { 0x00000040, "DELETE_CHILD" },
> +        { 0x00000080, "READ_ATTRIBUTES" },
> +        { 0x00000100, "WRITE_ATTRIBUTES" },
> +        { 0x00010000, "DELETE" },
> +        { 0x00020000, "READ_CONTROL" },
> +        { 0x00040000, "WRITE_DAC" },
> +        { 0x00080000, "WRITE_OWNER" },
> +        { 0x00100000, "SYNCHRONIZER" },
> +        { 0x01000000, "ACCESS_SYSTEM_SECURITY" },
> +        { 0x02000000, "MAXIMUM_ALLOWED" },
> +        { 0x10000000, "GENERIC_ALL" },
> +        { 0x20000000, "GENERIC_EXECUTE" },
> +        { 0x40000000, "GENERIC_WRITE" },
> +        { 0x80000000, "GENERIC_READ" },
> +        { 0, NULL }
> +};
> +
> +static void
> +print_bits(uint32_t mask, struct bit_string *bs)
> +{
> +        while (bs->string) {
> +               if (mask & bs->bit)
> +                    printf("%s ", bs->string);
> +                bs++;
> +        }
> +}
> +
> +static void
> +print_fileaccessinfo(uint8_t *sd, int type)
> +{
> +        uint32_t access_flags;
> +
> +        memcpy(&access_flags, &sd[0], 4);
> +        access_flags = le32toh(access_flags);
> +
> +        if (type == S_IFDIR) {
> +                printf("Directory access flags 0x%08x: ", access_flags);
> +                print_bits(access_flags, directory_access_mask);
> +        } else {
> +                printf("File/Printer access flags 0x%08x: ", access_flags);
> +                print_bits(access_flags, file_access_mask);
> +        }
> +        printf("\n");
> +}
> +
> +static void
> +fileaccessinfo(int f)
> +{
> +        struct smb_query_info *qi;
> +       struct stat st;
> +
> +       fstat(f, &st);
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 4);
> +       memset(qi, 0, sizeof(qi) + 4);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 8;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 4;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_fileaccessinfo((uint8_t *)(&qi[1]), st.st_mode & S_IFMT);
> +       free(qi);
> +}
> +
> +static void
> +print_filealigninfo(uint8_t *sd)
> +{
> +        uint32_t mask;
> +
> +        memcpy(&mask, &sd[0], 4);
> +        mask = le32toh(mask);
> +
> +        printf("File alignment: ");
> +        if (mask == 0)
> +                printf("BYTE_ALIGNMENT");
> +        else if (mask == 1)
> +                printf("WORD_ALIGNMENT");
> +        else if (mask == 3)
> +                printf("LONG_ALIGNMENT");
> +        else if (mask == 7)
> +                printf("QUAD_ALIGNMENT");
> +        else if (mask == 15)
> +                printf("OCTA_ALIGNMENT");
> +        else if (mask == 31)
> +                printf("32_bit_ALIGNMENT");
> +        else if (mask == 63)
> +                printf("64_bit_ALIGNMENT");
> +        else if (mask == 127)
> +                printf("128_bit_ALIGNMENT");
> +        else if (mask == 255)
> +                printf("254_bit_ALIGNMENT");
> +        else if (mask == 511)
> +                printf("512_bit_ALIGNMENT");
> +
> +        printf("\n");
> +}
> +
> +static void
> +filealigninfo(int f)
> +{
> +        struct smb_query_info *qi;
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 4);
> +       memset(qi, 0, sizeof(qi) + 4);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 17;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 4;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_filealigninfo((uint8_t *)(&qi[1]));
> +       free(qi);
> +}
> +
> +struct bit_string file_attributes_mask[] = {
> +        { 0x00000001, "READ_ONLY" },
> +        { 0x00000002, "HIDDEN" },
> +        { 0x00000004, "SYSTEM" },
> +        { 0x00000010, "DIRECTORY" },
> +        { 0x00000020, "ARCHIVE" },
> +        { 0x00000080, "NORMAL" },
> +        { 0x00000100, "TEMPORARY" },
> +        { 0x00000200, "SPARSE_FILE" },
> +        { 0x00000400, "REPARSE_POINT" },
> +        { 0x00000800, "COMPRESSED" },
> +        { 0x00001000, "OFFLINE" },
> +        { 0x00002000, "NOT_CONTENT_INDEXED" },
> +        { 0x00004000, "ENCRYPTED" },
> +        { 0x00008000, "INTEGRITY_STREAM" },
> +        { 0x00020000, "NO_SCRUB_DATA" },
> +        { 0, NULL }
> +};
> +
> +static void
> +print_filebasicinfo(uint8_t *sd)
> +{
> +        struct timeval tv;
> +        uint64_t u64;
> +        uint32_t u32;
> +
> +        memcpy(&u64, &sd[0], 8);
> +        win_to_timeval(le64toh(u64), &tv);
> +        printf("Creation Time %s", ctime(&tv.tv_sec));
> +
> +        memcpy(&u64, &sd[8], 8);
> +        win_to_timeval(le64toh(u64), &tv);
> +        printf("Last Access Time %s", ctime(&tv.tv_sec));
> +
> +        memcpy(&u64, &sd[16], 8);
> +        win_to_timeval(le64toh(u64), &tv);
> +        printf("Last Write Time %s", ctime(&tv.tv_sec));
> +
> +        memcpy(&u64, &sd[24], 8);
> +        win_to_timeval(le64toh(u64), &tv);
> +        printf("Last Change Time %s", ctime(&tv.tv_sec));
> +
> +        memcpy(&u32, &sd[32], 4);
> +        u32 = le32toh(u32);
> +       printf("File Attributes 0x%08x: ", u32);
> +       print_bits(u32, file_attributes_mask);
> +        printf("\n");
> +}
> +
> +static void
> +filebasicinfo(int f)
> +{
> +        struct smb_query_info *qi;
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 40);
> +       memset(qi, 0, sizeof(qi) + 40);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 4;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 40;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_filebasicinfo((uint8_t *)(&qi[1]));
> +       free(qi);
> +}
> +
> +static void
> +print_filestandardinfo(uint8_t *sd)
> +{
> +        uint64_t u64;
> +        uint32_t u32;
> +
> +        memcpy(&u64, &sd[0], 8);
> +        printf("Allocation Size %" PRIu64 "\n", le64toh(u64));
> +
> +        memcpy(&u64, &sd[8], 8);
> +        printf("End Of File %" PRIu64 "\n", le64toh(u64));
> +
> +        memcpy(&u32, &sd[16], 4);
> +        printf("Number Of Links %" PRIu32 "\n", le32toh(u32));
> +
> +       printf("Delete Pending %d\n", sd[20]);
> +       printf("Delete Directory %d\n", sd[21]);
> +}
> +
> +static void
> +filestandardinfo(int f)
> +{
> +        struct smb_query_info *qi;
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 24);
> +       memset(qi, 0, sizeof(qi) + 24);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 5;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 24;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_filestandardinfo((uint8_t *)(&qi[1]));
> +       free(qi);
> +}
> +
> +static void
> +print_fileinternalinfo(uint8_t *sd)
> +{
> +        uint64_t u64;
> +
> +        memcpy(&u64, &sd[0], 8);
> +        printf("Index Number %" PRIu64 "\n", le64toh(u64));
> +}
> +
> +static void
> +fileinternalinfo(int f)
> +{
> +        struct smb_query_info *qi;
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 8);
> +       memset(qi, 0, sizeof(qi) + 8);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 6;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 8;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_fileinternalinfo((uint8_t *)(&qi[1]));
> +       free(qi);
> +}
> +
> +struct bit_string file_mode_mask[] = {
> +        { 0x00000002, "WRITE_THROUGH" },
> +        { 0x00000004, "SEQUENTIAL_ONLY" },
> +        { 0x00000008, "NO_INTERMEDIATE_BUFFERING" },
> +        { 0x00000010, "SYNCHRONOUS_IO_ALERT" },
> +        { 0x00000020, "SYNCHRONOUS_IO_NONALERT" },
> +        { 0x00001000, "DELETE_ON_CLOSE" },
> +        { 0, NULL }
> +};
> +
> +static void
> +print_filemodeinfo(uint8_t *sd)
> +{
> +        uint32_t u32;
> +
> +        memcpy(&u32, &sd[32], 4);
> +        u32 = le32toh(u32);
> +       printf("Mode 0x%08x: ", u32);
> +       print_bits(u32, file_mode_mask);
> +        printf("\n");
> +}
> +
> +static void
> +filemodeinfo(int f)
> +{
> +        struct smb_query_info *qi;
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 4);
> +       memset(qi, 0, sizeof(qi) + 4);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 16;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 4;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_filemodeinfo((uint8_t *)(&qi[1]));
> +       free(qi);
> +}
> +
> +static void
> +print_filepositioninfo(uint8_t *sd)
> +{
> +        uint64_t u64;
> +
> +        memcpy(&u64, &sd[0], 8);
> +        printf("Current Byte Offset %" PRIu64 "\n", le64toh(u64));
> +}
> +
> +static void
> +filepositioninfo(int f)
> +{
> +        struct smb_query_info *qi;
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 8);
> +       memset(qi, 0, sizeof(qi) + 8);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 14;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 8;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_filepositioninfo((uint8_t *)(&qi[1]));
> +       free(qi);
> +}
> +
> +static void
> +print_fileeainfo(uint8_t *sd)
> +{
> +        uint32_t u32;
> +
> +        memcpy(&u32, &sd[0], 4);
> +        printf("Ea Size %" PRIu32 "\n", le32toh(u32));
> +}
> +
> +static void
> +fileeainfo(int f)
> +{
> +        struct smb_query_info *qi;
> +
> +        qi = malloc(sizeof(struct smb_query_info) + 4);
> +       memset(qi, 0, sizeof(qi) + 4);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 7;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = 4;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_fileeainfo((uint8_t *)(&qi[1]));
> +       free(qi);
> +}
> +
> +static void
> +fileallinfo(int f)
> +{
> +        struct smb_query_info *qi;
> +       struct stat st;
> +
> +       fstat(f, &st);
> +
> +        qi = malloc(sizeof(struct smb_query_info) + INPUT_BUFFER_LENGTH);
> +       memset(qi, 0, sizeof(qi) + INPUT_BUFFER_LENGTH);
> +        qi->info_type = 0x01;
> +        qi->file_info_class = 18;
> +        qi->additional_information = 0;
> +        qi->input_buffer_length = INPUT_BUFFER_LENGTH;
> +
> +        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
> +                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
> +                exit(1);
> +        }
> +
> +        print_filebasicinfo((uint8_t *)(&qi[1]));
> +        print_filestandardinfo((uint8_t *)(&qi[1]) + 40);
> +        print_fileinternalinfo((uint8_t *)(&qi[1]) + 64);
> +        print_fileeainfo((uint8_t *)(&qi[1]) + 72);
> +        print_fileaccessinfo((uint8_t *)(&qi[1]) + 76, st.st_mode & S_IFMT);
> +        print_filepositioninfo((uint8_t *)(&qi[1]) + 80);
> +        print_filemodeinfo((uint8_t *)(&qi[1]) + 88);
> +        print_filealigninfo((uint8_t *)(&qi[1]) + 92);
> +        // SMB2 servers like Win16 does not seem to return name info
> +       free(qi);
> +}
> +
> +static void
>  print_sid(unsigned char *sd)
>  {
>          int i;
> @@ -152,10 +593,13 @@ print_sd(uint8_t *sd)
>          }
>  }
>
> -void secdesc(int f) {
> +static void
> +secdesc(int f)
> +{
>          struct smb_query_info *qi;
>
>          qi = malloc(sizeof(struct smb_query_info) + INPUT_BUFFER_LENGTH);
> +       memset(qi, 0, sizeof(qi) + INPUT_BUFFER_LENGTH);
>          qi->info_type = 0x03;
>          qi->file_info_class = 0;
>          qi->additional_information = 0x00000007; /* Owner, Group, Dacl */
> @@ -167,13 +611,7 @@ void secdesc(int f) {
>          }
>
>          print_sd((uint8_t *)(&qi[1]));
> -}
> -
> -void
> -win_to_timeval(uint64_t smb2_time, struct timeval *tv)
> -{
> -  tv->tv_usec = (smb2_time / 10) % 1000000;
> -  tv->tv_sec  = (smb2_time - 116444736000000000) / 10000000;
> +       free(qi);
>  }
>
>  static void
> @@ -236,7 +674,9 @@ print_quota(unsigned char *sd)
>          }
>  }
>
> -void quota(int f) {
> +static void
> +quota(int f)
> +{
>          struct smb_query_info *qi;
>          char *buf;
>          int i;
> @@ -264,6 +704,7 @@ void quota(int f) {
>          }
>
>          print_quota((unsigned char *)(&qi[1]));
> +       free(qi);
>  }
>
>  int main(int argc, char *argv[])
> @@ -290,11 +731,29 @@ int main(int argc, char *argv[])
>          }
>
>
> -        if (!strcmp(argv[1], "secdesc")) {
> +        if (!strcmp(argv[1], "fileaccessinfo"))
> +                fileaccessinfo(f);
> +        else if (!strcmp(argv[1], "filealigninfo"))
> +                filealigninfo(f);
> +        else if (!strcmp(argv[1], "fileallinfo"))
> +                fileallinfo(f);
> +        else if (!strcmp(argv[1], "filebasicinfo"))
> +                filebasicinfo(f);
> +        else if (!strcmp(argv[1], "fileeainfo"))
> +                fileeainfo(f);
> +        else if (!strcmp(argv[1], "fileinternalinfo"))
> +                fileinternalinfo(f);
> +        else if (!strcmp(argv[1], "filemodeinfo"))
> +                filemodeinfo(f);
> +        else if (!strcmp(argv[1], "filepositioninfo"))
> +                filepositioninfo(f);
> +        else if (!strcmp(argv[1], "filestandardinfo"))
> +                filestandardinfo(f);
> +        else if (!strcmp(argv[1], "secdesc"))
>                  secdesc(f);
> -        } else if (!strcmp(argv[1], "quota")) {
> +        else if (!strcmp(argv[1], "quota"))
>                  quota(f);
> -        } else {
> +        else {
>                  fprintf(stderr, "Unknown command %s\n", argv[optind]);
>                  exit(1);
>          }
> diff --git a/smbinfo.rst b/smbinfo.rst
> index e37c709..2119f93 100644
> --- a/smbinfo.rst
> +++ b/smbinfo.rst
> @@ -39,14 +39,23 @@ OPTIONS
>  COMMAND
>  *******
>
> -`secdesc`: Print the security descriptor in the form
> -- Revision
> -- Control
> -- Owner SID
> -- Group SID
> -- ACL
> -- File types
> -- File flags
> +`fileaccessinfo`: Prints the FileAccessInformation class
> +
> +`filealigninfo`: Prints the FileAlignmentInformation class
> +
> +`fileallinfo`: Prints the FileAllInformation class
> +
> +`filebasicinfo`: Prints the FileBasicInformation class
> +
> +`fileeainfo`: Prints the FileEaInformation class
> +
> +`fileinternalinfo`: Prints the FileInternalInformation class
> +
> +`filemodeinfo`: Prints the FileModeInformation class
> +
> +`filepositioninfo`: Prints the FilePositionInformation class
> +
> +`filestandardinfo`: Prints the FileStandardInformation class
>
>  `quota`: Print the quota for the volume in the form
>  - SID Length
> @@ -56,6 +65,15 @@ COMMAND
>  - Quota Limit
>  - SID
>
> +`secdesc`: Print the security descriptor in the form
> +- Revision
> +- Control
> +- Owner SID
> +- Group SID
> +- ACL
> +- File types
> +- File flags
> +
>  *****
>  NOTES
>  *****
> --
> 2.13.6
>
diff mbox series

Patch

diff --git a/smbinfo.c b/smbinfo.c
index b1c129b..de9ebf6 100644
--- a/smbinfo.c
+++ b/smbinfo.c
@@ -66,6 +66,447 @@  usage(char *name)
 }
 
 static void
+win_to_timeval(uint64_t smb2_time, struct timeval *tv)
+{
+  tv->tv_usec = (smb2_time / 10) % 1000000;
+  tv->tv_sec  = (smb2_time - 116444736000000000) / 10000000;
+}
+
+struct bit_string {
+        unsigned int bit;
+        char *string;
+};
+
+struct bit_string directory_access_mask[] = {
+        { 0x00000001, "LIST_DIRECTORY" },
+        { 0x00000002, "ADD_FILE" },
+        { 0x00000004, "ADD_SUBDIRECTORY" },
+        { 0x00000008, "READ_EA" },
+        { 0x00000010, "WRITE_EA" },
+        { 0x00000020, "TRAVERSE" },
+        { 0x00000040, "DELETE_CHILD" },
+        { 0x00000080, "READ_ATTRIBUTES" },
+        { 0x00000100, "WRITE_ATTRIBUTES" },
+        { 0x00010000, "DELETE" },
+        { 0x00020000, "READ_CONTROL" },
+        { 0x00040000, "WRITE_DAC" },
+        { 0x00080000, "WRITE_OWNER" },
+        { 0x00100000, "SYNCHRONIZER" },
+        { 0x01000000, "ACCESS_SYSTEM_SECURITY" },
+        { 0x02000000, "MAXIMUM_ALLOWED" },
+        { 0x10000000, "GENERIC_ALL" },
+        { 0x20000000, "GENERIC_EXECUTE" },
+        { 0x40000000, "GENERIC_WRITE" },
+        { 0x80000000, "GENERIC_READ" },
+        { 0, NULL }
+};
+
+struct bit_string file_access_mask[] = {
+        { 0x00000001, "READ_DATA" },
+        { 0x00000002, "WRITE_DATA" },
+        { 0x00000004, "APPEND_DATA" },
+        { 0x00000008, "READ_EA" },
+        { 0x00000010, "WRITE_EA" },
+        { 0x00000020, "EXECUTE" },
+        { 0x00000040, "DELETE_CHILD" },
+        { 0x00000080, "READ_ATTRIBUTES" },
+        { 0x00000100, "WRITE_ATTRIBUTES" },
+        { 0x00010000, "DELETE" },
+        { 0x00020000, "READ_CONTROL" },
+        { 0x00040000, "WRITE_DAC" },
+        { 0x00080000, "WRITE_OWNER" },
+        { 0x00100000, "SYNCHRONIZER" },
+        { 0x01000000, "ACCESS_SYSTEM_SECURITY" },
+        { 0x02000000, "MAXIMUM_ALLOWED" },
+        { 0x10000000, "GENERIC_ALL" },
+        { 0x20000000, "GENERIC_EXECUTE" },
+        { 0x40000000, "GENERIC_WRITE" },
+        { 0x80000000, "GENERIC_READ" },
+        { 0, NULL }
+};
+
+static void
+print_bits(uint32_t mask, struct bit_string *bs)
+{
+        while (bs->string) {
+		if (mask & bs->bit)
+                    printf("%s ", bs->string);
+                bs++;
+        }
+}
+
+static void
+print_fileaccessinfo(uint8_t *sd, int type)
+{
+        uint32_t access_flags;
+
+        memcpy(&access_flags, &sd[0], 4);
+        access_flags = le32toh(access_flags);
+
+        if (type == S_IFDIR) {
+                printf("Directory access flags 0x%08x: ", access_flags);
+                print_bits(access_flags, directory_access_mask);
+        } else {
+                printf("File/Printer access flags 0x%08x: ", access_flags);
+                print_bits(access_flags, file_access_mask);
+        }
+        printf("\n");
+}
+
+static void
+fileaccessinfo(int f)
+{
+        struct smb_query_info *qi;
+	struct stat st;
+
+	fstat(f, &st);
+
+        qi = malloc(sizeof(struct smb_query_info) + 4);
+	memset(qi, 0, sizeof(qi) + 4);
+        qi->info_type = 0x01;
+        qi->file_info_class = 8;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 4;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_fileaccessinfo((uint8_t *)(&qi[1]), st.st_mode & S_IFMT);
+	free(qi);
+}
+
+static void
+print_filealigninfo(uint8_t *sd)
+{
+        uint32_t mask;
+
+        memcpy(&mask, &sd[0], 4);
+        mask = le32toh(mask);
+
+        printf("File alignment: ");
+        if (mask == 0)
+                printf("BYTE_ALIGNMENT");
+        else if (mask == 1)
+                printf("WORD_ALIGNMENT");
+        else if (mask == 3)
+                printf("LONG_ALIGNMENT");
+        else if (mask == 7)
+                printf("QUAD_ALIGNMENT");
+        else if (mask == 15)
+                printf("OCTA_ALIGNMENT");
+        else if (mask == 31)
+                printf("32_bit_ALIGNMENT");
+        else if (mask == 63)
+                printf("64_bit_ALIGNMENT");
+        else if (mask == 127)
+                printf("128_bit_ALIGNMENT");
+        else if (mask == 255)
+                printf("254_bit_ALIGNMENT");
+        else if (mask == 511)
+                printf("512_bit_ALIGNMENT");
+
+        printf("\n");
+}
+
+static void
+filealigninfo(int f)
+{
+        struct smb_query_info *qi;
+
+        qi = malloc(sizeof(struct smb_query_info) + 4);
+	memset(qi, 0, sizeof(qi) + 4);
+        qi->info_type = 0x01;
+        qi->file_info_class = 17;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 4;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_filealigninfo((uint8_t *)(&qi[1]));
+	free(qi);
+}
+
+struct bit_string file_attributes_mask[] = {
+        { 0x00000001, "READ_ONLY" },
+        { 0x00000002, "HIDDEN" },
+        { 0x00000004, "SYSTEM" },
+        { 0x00000010, "DIRECTORY" },
+        { 0x00000020, "ARCHIVE" },
+        { 0x00000080, "NORMAL" },
+        { 0x00000100, "TEMPORARY" },
+        { 0x00000200, "SPARSE_FILE" },
+        { 0x00000400, "REPARSE_POINT" },
+        { 0x00000800, "COMPRESSED" },
+        { 0x00001000, "OFFLINE" },
+        { 0x00002000, "NOT_CONTENT_INDEXED" },
+        { 0x00004000, "ENCRYPTED" },
+        { 0x00008000, "INTEGRITY_STREAM" },
+        { 0x00020000, "NO_SCRUB_DATA" },
+        { 0, NULL }
+};
+
+static void
+print_filebasicinfo(uint8_t *sd)
+{
+        struct timeval tv;
+        uint64_t u64;
+        uint32_t u32;
+
+        memcpy(&u64, &sd[0], 8);
+        win_to_timeval(le64toh(u64), &tv);
+        printf("Creation Time %s", ctime(&tv.tv_sec));
+
+        memcpy(&u64, &sd[8], 8);
+        win_to_timeval(le64toh(u64), &tv);
+        printf("Last Access Time %s", ctime(&tv.tv_sec));
+
+        memcpy(&u64, &sd[16], 8);
+        win_to_timeval(le64toh(u64), &tv);
+        printf("Last Write Time %s", ctime(&tv.tv_sec));
+
+        memcpy(&u64, &sd[24], 8);
+        win_to_timeval(le64toh(u64), &tv);
+        printf("Last Change Time %s", ctime(&tv.tv_sec));
+
+        memcpy(&u32, &sd[32], 4);
+        u32 = le32toh(u32);
+	printf("File Attributes 0x%08x: ", u32);
+	print_bits(u32, file_attributes_mask);
+        printf("\n");
+}
+
+static void
+filebasicinfo(int f)
+{
+        struct smb_query_info *qi;
+
+        qi = malloc(sizeof(struct smb_query_info) + 40);
+	memset(qi, 0, sizeof(qi) + 40);
+        qi->info_type = 0x01;
+        qi->file_info_class = 4;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 40;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_filebasicinfo((uint8_t *)(&qi[1]));
+	free(qi);
+}
+
+static void
+print_filestandardinfo(uint8_t *sd)
+{
+        uint64_t u64;
+        uint32_t u32;
+
+        memcpy(&u64, &sd[0], 8);
+        printf("Allocation Size %" PRIu64 "\n", le64toh(u64));
+	
+        memcpy(&u64, &sd[8], 8);
+        printf("End Of File %" PRIu64 "\n", le64toh(u64));
+	
+        memcpy(&u32, &sd[16], 4);
+        printf("Number Of Links %" PRIu32 "\n", le32toh(u32));
+
+	printf("Delete Pending %d\n", sd[20]);
+	printf("Delete Directory %d\n", sd[21]);
+}
+
+static void
+filestandardinfo(int f)
+{
+        struct smb_query_info *qi;
+
+        qi = malloc(sizeof(struct smb_query_info) + 24);
+	memset(qi, 0, sizeof(qi) + 24);
+        qi->info_type = 0x01;
+        qi->file_info_class = 5;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 24;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_filestandardinfo((uint8_t *)(&qi[1]));
+	free(qi);
+}
+
+static void
+print_fileinternalinfo(uint8_t *sd)
+{
+        uint64_t u64;
+
+        memcpy(&u64, &sd[0], 8);
+        printf("Index Number %" PRIu64 "\n", le64toh(u64));
+}
+
+static void
+fileinternalinfo(int f)
+{
+        struct smb_query_info *qi;
+
+        qi = malloc(sizeof(struct smb_query_info) + 8);
+	memset(qi, 0, sizeof(qi) + 8);
+        qi->info_type = 0x01;
+        qi->file_info_class = 6;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 8;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_fileinternalinfo((uint8_t *)(&qi[1]));
+	free(qi);
+}
+
+struct bit_string file_mode_mask[] = {
+        { 0x00000002, "WRITE_THROUGH" },
+        { 0x00000004, "SEQUENTIAL_ONLY" },
+        { 0x00000008, "NO_INTERMEDIATE_BUFFERING" },
+        { 0x00000010, "SYNCHRONOUS_IO_ALERT" },
+        { 0x00000020, "SYNCHRONOUS_IO_NONALERT" },
+        { 0x00001000, "DELETE_ON_CLOSE" },
+        { 0, NULL }
+};
+
+static void
+print_filemodeinfo(uint8_t *sd)
+{
+        uint32_t u32;
+
+        memcpy(&u32, &sd[32], 4);
+        u32 = le32toh(u32);
+	printf("Mode 0x%08x: ", u32);
+	print_bits(u32, file_mode_mask);
+        printf("\n");
+}
+
+static void
+filemodeinfo(int f)
+{
+        struct smb_query_info *qi;
+
+        qi = malloc(sizeof(struct smb_query_info) + 4);
+	memset(qi, 0, sizeof(qi) + 4);
+        qi->info_type = 0x01;
+        qi->file_info_class = 16;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 4;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_filemodeinfo((uint8_t *)(&qi[1]));
+	free(qi);
+}
+
+static void
+print_filepositioninfo(uint8_t *sd)
+{
+        uint64_t u64;
+
+        memcpy(&u64, &sd[0], 8);
+        printf("Current Byte Offset %" PRIu64 "\n", le64toh(u64));
+}
+
+static void
+filepositioninfo(int f)
+{
+        struct smb_query_info *qi;
+
+        qi = malloc(sizeof(struct smb_query_info) + 8);
+	memset(qi, 0, sizeof(qi) + 8);
+        qi->info_type = 0x01;
+        qi->file_info_class = 14;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 8;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_filepositioninfo((uint8_t *)(&qi[1]));
+	free(qi);
+}
+
+static void
+print_fileeainfo(uint8_t *sd)
+{
+        uint32_t u32;
+
+        memcpy(&u32, &sd[0], 4);
+        printf("Ea Size %" PRIu32 "\n", le32toh(u32));
+}
+
+static void
+fileeainfo(int f)
+{
+        struct smb_query_info *qi;
+
+        qi = malloc(sizeof(struct smb_query_info) + 4);
+	memset(qi, 0, sizeof(qi) + 4);
+        qi->info_type = 0x01;
+        qi->file_info_class = 7;
+        qi->additional_information = 0;
+        qi->input_buffer_length = 4;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_fileeainfo((uint8_t *)(&qi[1]));
+	free(qi);
+}
+
+static void
+fileallinfo(int f)
+{
+        struct smb_query_info *qi;
+	struct stat st;
+
+	fstat(f, &st);
+
+        qi = malloc(sizeof(struct smb_query_info) + INPUT_BUFFER_LENGTH);
+	memset(qi, 0, sizeof(qi) + INPUT_BUFFER_LENGTH);
+        qi->info_type = 0x01;
+        qi->file_info_class = 18;
+        qi->additional_information = 0;
+        qi->input_buffer_length = INPUT_BUFFER_LENGTH;
+
+        if (ioctl(f, CIFS_QUERY_INFO, qi) < 0) {
+                fprintf(stderr, "ioctl failed with %s\n", strerror(errno));
+                exit(1);
+        }
+
+        print_filebasicinfo((uint8_t *)(&qi[1]));
+        print_filestandardinfo((uint8_t *)(&qi[1]) + 40);
+        print_fileinternalinfo((uint8_t *)(&qi[1]) + 64);
+        print_fileeainfo((uint8_t *)(&qi[1]) + 72);
+        print_fileaccessinfo((uint8_t *)(&qi[1]) + 76, st.st_mode & S_IFMT);
+        print_filepositioninfo((uint8_t *)(&qi[1]) + 80);
+        print_filemodeinfo((uint8_t *)(&qi[1]) + 88);
+        print_filealigninfo((uint8_t *)(&qi[1]) + 92);
+        // SMB2 servers like Win16 does not seem to return name info
+	free(qi);
+}
+
+static void
 print_sid(unsigned char *sd)
 {
         int i;
@@ -152,10 +593,13 @@  print_sd(uint8_t *sd)
         }
 }
 
-void secdesc(int f) {
+static void
+secdesc(int f)
+{
         struct smb_query_info *qi;
 
         qi = malloc(sizeof(struct smb_query_info) + INPUT_BUFFER_LENGTH);
+	memset(qi, 0, sizeof(qi) + INPUT_BUFFER_LENGTH);
         qi->info_type = 0x03;
         qi->file_info_class = 0;
         qi->additional_information = 0x00000007; /* Owner, Group, Dacl */
@@ -167,13 +611,7 @@  void secdesc(int f) {
         }
 
         print_sd((uint8_t *)(&qi[1]));
-}
-
-void
-win_to_timeval(uint64_t smb2_time, struct timeval *tv)
-{
-  tv->tv_usec = (smb2_time / 10) % 1000000;
-  tv->tv_sec  = (smb2_time - 116444736000000000) / 10000000;
+	free(qi);
 }
 
 static void
@@ -236,7 +674,9 @@  print_quota(unsigned char *sd)
         }
 }
 
-void quota(int f) {
+static void
+quota(int f)
+{
         struct smb_query_info *qi;
         char *buf;
         int i;
@@ -264,6 +704,7 @@  void quota(int f) {
         }
 
         print_quota((unsigned char *)(&qi[1]));
+	free(qi);
 }
 
 int main(int argc, char *argv[])
@@ -290,11 +731,29 @@  int main(int argc, char *argv[])
         }
 
 
-        if (!strcmp(argv[1], "secdesc")) {
+        if (!strcmp(argv[1], "fileaccessinfo"))
+                fileaccessinfo(f);
+        else if (!strcmp(argv[1], "filealigninfo"))
+                filealigninfo(f);
+        else if (!strcmp(argv[1], "fileallinfo"))
+                fileallinfo(f);
+        else if (!strcmp(argv[1], "filebasicinfo"))
+                filebasicinfo(f);
+        else if (!strcmp(argv[1], "fileeainfo"))
+                fileeainfo(f);
+        else if (!strcmp(argv[1], "fileinternalinfo"))
+                fileinternalinfo(f);
+        else if (!strcmp(argv[1], "filemodeinfo"))
+                filemodeinfo(f);
+        else if (!strcmp(argv[1], "filepositioninfo"))
+                filepositioninfo(f);
+        else if (!strcmp(argv[1], "filestandardinfo"))
+                filestandardinfo(f);
+        else if (!strcmp(argv[1], "secdesc"))
                 secdesc(f);
-        } else if (!strcmp(argv[1], "quota")) {
+        else if (!strcmp(argv[1], "quota"))
                 quota(f);
-        } else {
+        else {
                 fprintf(stderr, "Unknown command %s\n", argv[optind]);
                 exit(1);
         }
diff --git a/smbinfo.rst b/smbinfo.rst
index e37c709..2119f93 100644
--- a/smbinfo.rst
+++ b/smbinfo.rst
@@ -39,14 +39,23 @@  OPTIONS
 COMMAND
 *******
 
-`secdesc`: Print the security descriptor in the form
-- Revision
-- Control
-- Owner SID
-- Group SID
-- ACL
-- File types
-- File flags
+`fileaccessinfo`: Prints the FileAccessInformation class
+
+`filealigninfo`: Prints the FileAlignmentInformation class
+
+`fileallinfo`: Prints the FileAllInformation class
+
+`filebasicinfo`: Prints the FileBasicInformation class
+
+`fileeainfo`: Prints the FileEaInformation class
+
+`fileinternalinfo`: Prints the FileInternalInformation class
+
+`filemodeinfo`: Prints the FileModeInformation class
+
+`filepositioninfo`: Prints the FilePositionInformation class
+
+`filestandardinfo`: Prints the FileStandardInformation class
 
 `quota`: Print the quota for the volume in the form
 - SID Length
@@ -56,6 +65,15 @@  COMMAND
 - Quota Limit
 - SID
 
+`secdesc`: Print the security descriptor in the form
+- Revision
+- Control
+- Owner SID
+- Group SID
+- ACL
+- File types
+- File flags
+
 *****
 NOTES
 *****