| .\" Copyright (C) 2014, Heinrich Schuchardt <xypron.glpk@gmx.de> |
| .\" |
| .\" %%%LICENSE_START(VERBATIM) |
| .\" Permission is granted to make and distribute verbatim copies of this |
| .\" manual provided the copyright notice and this permission notice are |
| .\" preserved on all copies. |
| .\" |
| .\" Permission is granted to copy and distribute modified versions of |
| .\" this manual under the conditions for verbatim copying, provided that |
| .\" the entire resulting derived work is distributed under the terms of |
| .\" a permission notice identical to this one. |
| .\" |
| .\" Since the Linux kernel and libraries are constantly changing, this |
| .\" manual page may be incorrect or out-of-date. The author(s) assume |
| .\" no responsibility for errors or omissions, or for damages resulting |
| .\" from the use of the information contained herein. The author(s) may |
| .\" not have taken the same level of care in the production of this |
| .\" manual, which is licensed free of charge, as they might when working |
| .\" professionally. |
| .\" |
| .\" Formatted or processed versions of this manual, if unaccompanied by |
| .\" the source, must acknowledge the copyright and authors of this work. |
| .\" %%%LICENSE_END |
| .TH IOCTL_FAT 2 2021-03-22 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| ioctl_fat \- manipulating the FAT filesystem |
| .SH SYNOPSIS |
| .nf |
| .BR "#include <linux/msdos_fs.h>" " /* Definition of [" V ] FAT_* " and" |
| .BR " ATTR_* " constants */" |
| .B #include <sys/ioctl.h> |
| .PP |
| .BI "int ioctl(int " fd ", FAT_IOCTL_GET_ATTRIBUTES, uint32_t *" attr ); |
| .BI "int ioctl(int " fd ", FAT_IOCTL_SET_ATTRIBUTES, uint32_t *" attr ); |
| .BI "int ioctl(int " fd ", FAT_IOCTL_GET_VOLUME_ID, uint32_t *" id ); |
| .BI "int ioctl(int " fd ", VFAT_IOCTL_READDIR_BOTH," |
| .BI " struct __fat_dirent " entry [2]); |
| .BI "int ioctl(int " fd ", VFAT_IOCTL_READDIR_SHORT," |
| .BI " struct __fat_dirent " entry [2]); |
| .fi |
| .SH DESCRIPTION |
| The |
| .BR ioctl (2) |
| system call can be used to read and write metadata of FAT filesystems that |
| are not accessible using other system calls. |
| .SS Reading and setting file attributes |
| Files and directories in the FAT filesystem possess an attribute bit mask that |
| can be read with |
| .B FAT_IOCTL_GET_ATTRIBUTES |
| and written with |
| .BR FAT_IOCTL_SET_ATTRIBUTES . |
| .PP |
| The |
| .I fd |
| argument contains a file descriptor for a file or directory. |
| It is sufficient to create the file descriptor by calling |
| .BR open (2) |
| with the |
| .B O_RDONLY |
| flag. |
| .PP |
| The |
| .I attr |
| argument contains a pointer to a bit mask. |
| The bits of the bit mask are: |
| .TP |
| .B ATTR_RO |
| This bit specifies that the file or directory is read-only. |
| .TP |
| .B ATTR_HIDDEN |
| This bit specifies that the file or directory is hidden. |
| .TP |
| .B ATTR_SYS |
| This bit specifies that the file is a system file. |
| .TP |
| .B ATTR_VOLUME |
| This bit specifies that the file is a volume label. |
| This attribute is read-only. |
| .TP |
| .B ATTR_DIR |
| This bit specifies that this is a directory. |
| This attribute is read-only. |
| .TP |
| .B ATTR_ARCH |
| This bit indicates that this file or directory should be archived. |
| It is set when a file is created or modified. |
| It is reset by an archiving system. |
| .PP |
| The zero value |
| .B ATTR_NONE |
| can be used to indicate that no attribute bit is set. |
| .SS Reading the volume ID |
| FAT filesystems are identified by a volume ID. |
| The volume ID can be read with |
| .BR FAT_IOCTL_GET_VOLUME_ID . |
| .PP |
| The |
| .I fd |
| argument can be a file descriptor for any file or directory of the |
| filesystem. |
| It is sufficient to create the file descriptor by calling |
| .BR open (2) |
| with the |
| .B O_RDONLY |
| flag. |
| .PP |
| The |
| .I id |
| argument is a pointer to the field that will be filled with the volume ID. |
| Typically the volume ID is displayed to the user as a group of two |
| 16-bit fields: |
| .PP |
| .in +4n |
| .EX |
| printf("Volume ID %04x\-%04x\en", id >> 16, id & 0xFFFF); |
| .EE |
| .in |
| .SS Reading short filenames of a directory |
| A file or directory on a FAT filesystem always has a short filename |
| consisting of up to 8 capital letters, optionally followed by a period |
| and up to 3 capital letters for the file extension. |
| If the actual filename does not fit into this scheme, it is stored |
| as a long filename of up to 255 UTF-16 characters. |
| .PP |
| The short filenames in a directory can be read with |
| .BR VFAT_IOCTL_READDIR_SHORT . |
| .B VFAT_IOCTL_READDIR_BOTH |
| reads both the short and the long filenames. |
| .PP |
| The |
| .I fd |
| argument must be a file descriptor for a directory. |
| It is sufficient to create the file descriptor by calling |
| .BR open (2) |
| with the |
| .B O_RDONLY |
| flag. |
| The file descriptor can be used only once to iterate over the directory |
| entries by calling |
| .BR ioctl (2) |
| repeatedly. |
| .PP |
| The |
| .I entry |
| argument is a two-element array of the following structures: |
| .PP |
| .in +4n |
| .EX |
| struct __fat_dirent { |
| long d_ino; |
| __kernel_off_t d_off; |
| uint32_t short d_reclen; |
| char d_name[256]; |
| }; |
| .EE |
| .in |
| .PP |
| The first entry in the array is for the short filename. |
| The second entry is for the long filename. |
| .PP |
| The |
| .I d_ino |
| and |
| .I d_off |
| fields are filled only for long filenames. |
| The |
| .I d_ino |
| field holds the inode number of the directory. |
| The |
| .I d_off |
| field holds the offset of the file entry in the directory. |
| As these values are not available for short filenames, the user code should |
| simply ignore them. |
| .PP |
| The field |
| .I d_reclen |
| contains the length of the filename in the field |
| .IR d_name . |
| To keep backward compatibility, a length of 0 for the short filename signals |
| that the end of the directory has been reached. |
| However, the preferred method for detecting the end of the directory |
| is to test the |
| .BR ioctl (2) |
| return value. |
| If no long filename exists, field |
| .I d_reclen |
| is set to 0 and |
| .I d_name |
| is a character string of length 0 for the long filename. |
| .SH RETURN VALUE |
| On error, \-1 is returned, and |
| .I errno |
| is set to indicate the error. |
| .PP |
| For |
| .B VFAT_IOCTL_READDIR_BOTH |
| and |
| .B VFAT_IOCTL_READDIR_SHORT |
| a return value of 1 signals that a new directory entry has been read and |
| a return value of 0 signals that the end of the directory has been reached. |
| .SH ERRORS |
| .TP |
| .B ENOENT |
| This error is returned by |
| .B VFAT_IOCTL_READDIR_BOTH |
| and |
| .B VFAT_IOCTL_READDIR_SHORT |
| if the file descriptor |
| .I fd |
| refers to a removed, but still open directory. |
| .TP |
| .B ENOTDIR |
| This error is returned by |
| .B VFAT_IOCTL_READDIR_BOTH |
| and |
| .B VFAT_IOCTL_READDIR_SHORT |
| if the file descriptor |
| .I fd |
| does not refer to a directory. |
| .TP |
| .B ENOTTY |
| The file descriptor |
| .I fd |
| does not refer to an object in a FAT filesystem. |
| .PP |
| For further error values, see |
| .BR ioctl (2). |
| .SH VERSIONS |
| .BR VFAT_IOCTL_READDIR_BOTH |
| and |
| .B VFAT_IOCTL_READDIR_SHORT |
| first appeared in Linux 2.0. |
| .PP |
| .BR FAT_IOCTL_GET_ATTRIBUTES |
| and |
| .BR FAT_IOCTL_SET_ATTRIBUTES |
| first appeared |
| .\" just before we got Git history |
| in Linux 2.6.12. |
| .PP |
| .B FAT_IOCTL_GET_VOLUME_ID |
| was introduced in version 3.11 |
| .\" commit 6e5b93ee55d401f1619092fb675b57c28c9ed7ec |
| of the Linux kernel. |
| .SH CONFORMING TO |
| This API is Linux-specific. |
| .SH EXAMPLES |
| .SS Toggling the archive flag |
| The following program demonstrates the usage of |
| .BR ioctl (2) |
| to manipulate file attributes. |
| The program reads and displays the archive attribute of a file. |
| After inverting the value of the attribute, |
| the program reads and displays the attribute again. |
| .PP |
| The following was recorded when applying the program for the file |
| .IR /mnt/user/foo : |
| .PP |
| .in +4n |
| .EX |
| # ./toggle_fat_archive_flag /mnt/user/foo |
| Archive flag is set |
| Toggling archive flag |
| Archive flag is not set |
| .EE |
| .in |
| .SS Program source (toggle_fat_archive_flag.c) |
| \& |
| .EX |
| #include <fcntl.h> |
| #include <linux/msdos_fs.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <unistd.h> |
| |
| /* |
| * Read file attributes of a file on a FAT filesystem. |
| * Output the state of the archive flag. |
| */ |
| static uint32_t |
| readattr(int fd) |
| { |
| uint32_t attr; |
| int ret; |
| |
| ret = ioctl(fd, FAT_IOCTL_GET_ATTRIBUTES, &attr); |
| if (ret == \-1) { |
| perror("ioctl"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (attr & ATTR_ARCH) |
| printf("Archive flag is set\en"); |
| else |
| printf("Archive flag is not set\en"); |
| |
| return attr; |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| uint32_t attr; |
| int fd; |
| int ret; |
| |
| if (argc != 2) { |
| printf("Usage: %s FILENAME\en", argv[0]); |
| exit(EXIT_FAILURE); |
| } |
| |
| fd = open(argv[1], O_RDONLY); |
| if (fd == \-1) { |
| perror("open"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* |
| * Read and display the FAT file attributes. |
| */ |
| attr = readattr(fd); |
| |
| /* |
| * Invert archive attribute. |
| */ |
| printf("Toggling archive flag\en"); |
| attr \(ha= ATTR_ARCH; |
| |
| /* |
| * Write the changed FAT file attributes. |
| */ |
| ret = ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); |
| if (ret == \-1) { |
| perror("ioctl"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* |
| * Read and display the FAT file attributes. |
| */ |
| readattr(fd); |
| |
| close(fd); |
| |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .\" |
| .SS Reading the volume ID |
| The following program demonstrates the use of |
| .BR ioctl (2) |
| to display the volume ID of a FAT filesystem. |
| .PP |
| The following output was recorded when applying the program for |
| directory |
| .IR /mnt/user : |
| .PP |
| .in +4n |
| .EX |
| $ ./display_fat_volume_id /mnt/user |
| Volume ID 6443\-6241 |
| .EE |
| .in |
| .SS Program source (display_fat_volume_id.c) |
| \& |
| .EX |
| #include <fcntl.h> |
| #include <linux/msdos_fs.h> |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <unistd.h> |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| uint32_t id; |
| int fd; |
| int ret; |
| |
| if (argc != 2) { |
| printf("Usage: %s FILENAME\en", argv[0]); |
| exit(EXIT_FAILURE); |
| } |
| |
| fd = open(argv[1], O_RDONLY); |
| if (fd == \-1) { |
| perror("open"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* |
| * Read volume ID. |
| */ |
| ret = ioctl(fd, FAT_IOCTL_GET_VOLUME_ID, &id); |
| if (ret == \-1) { |
| perror("ioctl"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* |
| * Format the output as two groups of 16 bits each. |
| */ |
| printf("Volume ID %04x\-%04x\en", id >> 16, id & 0xFFFF); |
| |
| close(fd); |
| |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .\" |
| .SS Listing a directory |
| The following program demonstrates the use of |
| .BR ioctl (2) |
| to list a directory. |
| .PP |
| The following was recorded when applying the program to the directory |
| .IR /mnt/user : |
| .PP |
| .in +4n |
| .EX |
| $ \fB./fat_dir /mnt/user\fP |
| \[char46] \-> \(aq\(aq |
| \[char46]. \-> \(aq\(aq |
| ALONGF\(ti1.TXT \-> \(aqa long filename.txt\(aq |
| UPPER.TXT \-> \(aq\(aq |
| LOWER.TXT \-> \(aqlower.txt\(aq |
| .EE |
| .in |
| .\" |
| .SS Program source |
| .in +4n |
| .EX |
| #include <fcntl.h> |
| #include <linux/msdos_fs.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/ioctl.h> |
| #include <unistd.h> |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| struct __fat_dirent entry[2]; |
| int fd; |
| int ret; |
| |
| if (argc != 2) { |
| printf("Usage: %s DIRECTORY\en", argv[0]); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* |
| * Open file descriptor for the directory. |
| */ |
| fd = open(argv[1], O_RDONLY | O_DIRECTORY); |
| if (fd == \-1) { |
| perror("open"); |
| exit(EXIT_FAILURE); |
| } |
| |
| for (;;) { |
| |
| /* |
| * Read next directory entry. |
| */ |
| ret = ioctl( fd, VFAT_IOCTL_READDIR_BOTH, entry); |
| |
| /* |
| * If an error occurs, the return value is \-1. |
| * If the end of the directory list has been reached, |
| * the return value is 0. |
| * For backward compatibility the end of the directory |
| * list is also signaled by d_reclen == 0. |
| */ |
| if (ret < 1) |
| break; |
| |
| /* |
| * Write both the short name and the long name. |
| */ |
| printf("%s \-> \(aq%s\(aq\en", entry[0].d_name, entry[1].d_name); |
| } |
| |
| if (ret == \-1) { |
| perror("VFAT_IOCTL_READDIR_BOTH"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* |
| * Close the file descriptor. |
| */ |
| close(fd); |
| |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .in |
| .SH SEE ALSO |
| .BR ioctl (2) |