How to get more vfat attributes of files in Linux using C? - c

This is a follow-up to my other question here:
How to read vfat attributes of files in Linux using C
--
I saw this struct in linux/msdos_fs.h:
struct msdos_dir_entry {
__u8 name[8],ext[3]; /* name and extension */
__u8 attr; /* attribute bits */
__u8 lcase; /* Case for base and extension */
__u8 ctime_cs; /* Creation time, centiseconds (0-199) */
__le16 ctime; /* Creation time */
__le16 cdate; /* Creation date */
__le16 adate; /* Last access date */
__le16 starthi; /* High 16 bits of cluster in FAT32 */
__le16 time,date,start;/* time, date and first cluster */
__le32 size; /* file size (in bytes) */
};
My question is, would it be possible to populate such a struct inside my user application? My app requirement is that it should be able traverse a vfat filesystem, and get the vfat attributes (msdos_dir_entry) for each directory/file it finds.
Thanks.

Actually you can get almost all of this by combining the information you can get from fstat(), the FAT_IOCTL_GET_ATTRIBUTES and VFAT_IOCTL_READDIR_BOTH ioctls. It's not going to nice to look at though, since for the fromer two you need the file fd and for the latter two you need the fd of the dir the file is located in.

Related

Linux kernel: help understanding xfs structs

I'm currently working on a project involving the exploration of the linux kernel, particularly the XFS filesystem , right now I'm trying to read where a file resides on disk and i stumbled upon the xfs_ifork struct which looks like:
typedef struct xfs_ifork {
int if_bytes; /* bytes in if_u1 */
int if_real_bytes; /* bytes allocated in if_u1 */
struct xfs_btree_block *if_broot; /* file's incore btree root */
short if_broot_bytes; /* bytes allocated for root */
unsigned char if_flags; /* per-fork flags */
union {
xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */
xfs_ext_irec_t *if_ext_irec; /* irec map file exts */
char *if_data; /* inline file data */
} if_u1;
union {
xfs_bmbt_rec_host_t if_inline_ext[XFS_INLINE_EXTS];
/* very small file extents */
char if_inline_data[XFS_INLINE_DATA];
/* very small file data */
xfs_dev_t if_rdev; /* dev number if special */
uuid_t if_uuid; /* mount point value */
} if_u2;
} xfs_ifork_t;
my lead on the u1 union, which encases different scenarios of file data fork, but i cant seem to have figured out the exact way to read them , the xfs_bmbt_rec_host_t struct refers to the disk address , written inside 2 uint64 types which encapsulates the entire address i need,
but somehow, the address I'm able to read isn't the correct one, so goes for the xfs_ext_irec_t struct, which holds the xfs_bmbt_rec_host_t struct and counters.
if someone happens to know theses structs well or have used them i would appreciate some explaining

how to use lstat() to determine if hard link or not

My OS is linux. I program in C. I know I can use the lstat() to recognize the soft link, i.e., use S_ISLNK(st.st_mode). But how can I recognize the link is hard link? if the link is hard link, it will be thought of as regular file. However, I also want to distinguish the regular file from the hard link. Are there any ways to handle this case?
But how can I recognize the link is hard link?
You can't.
A "hard link" isn't actually anything special. It's just a directory entry that happens to point to the same data on disk as a directory entry somewhere else. The only way to reliably identify hard links is to map all the paths on your filesystem to inodes, and then see which ones point to the same value.
struct stat has st_nlink member for number of hard links. It is > 1, file is being stated in one of the hard links to actual file content.
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for file system I/O */
blkcnt_t st_blocks; /* number of 512B blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
Here is sample program:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main()
{
struct stat buf = {0};
lstat("origfile", &buf);
printf("number of hard links for origfile: %d\n", buf.st_nlink);
}
output:
$ touch origfile
$ ./a.out
number of hard links for origfile: 1
$ ln origfile hardlink1
$ ./a.out
number of hard links for origfile: 2
$ ln origfile hardlink2
$ ./a.out
number of hard links for origfile: 3

Inline data extension for sfs_inode (OS161)

Hi I'm working with OS161 and I'm trying to extend my inode structures so that when I write to disk, I write the first chunk of file data into the actual inode structure, because currently it's set up such that a large chunk of the structure is wasted.
struct sfs_inode {
u_int32_t sfi_size; /* Size of this file (bytes) */
u_int16_t sfi_type; /* One of SFS_TYPE_* above */
u_int16_t sfi_linkcount; /* Number of hard links to this file */
u_int32_t sfi_direct[SFS_NDIRECT]; /* Direct blocks */
u_int32_t sfi_indirect; /* Indirect block */
u_int32_t sfi_waste[128-3-SFS_NDIRECT]; /* unused space */
};
I'd like to replace the sfi_waste above with a char sfi_inlinedata[INLINE_SIZE]; so that
my disk io will always write/read the first INLINE_SIZE of data to the sfs_inode struct.
The following is the source I'm working from for the relevant io functions. I know I need to change the way that the offset maps to actual addresses in the io functions here, but I'm having trouble coming up with a concrete solution.
https://github.com/rbui/projectJailBait/blob/master/os161-1.11/kern/fs/sfs/sfs_vnode.c
Any help would be much appreciated!

Is it possible getting and setting file name with struct stat descriptor?

Is it possible at get or set ( rename ) a file name with giving the absolute path of file, and a struct stat instance as parameters to lstat function. As I find in documentation struct seems like that;
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
What I want is something like that;
struct stat *s;
char *path; // assigning the ablosute path of file
int res = lstat(path, s);
if(res == -1)
return errno;
char *name = s->(someFielAboutFileName);
or
s->(someFieldAboutFileName) = name; // setting name
No. In unix, the name is not an inherent property of the file. A file can have multiple names (see hard links) or even none.
The names are just entries in directories.
In Unix, the name of the file belongs to the directory, not the file. Meaning, the same file can have multiple names (it's called "hard links" in Unix). This also means you can not find out the name from stat, since it deals with files, not names. You can use realpath to find real name of the file, with resolving symlinks, etc.
It seems that you want to modify a symbolic link. lstat() won't help you with that, as it only returns the status of the link, not even the name of the file it points to, and cannot be used to modify anything about the file anyway.
You'll probably have to unlink() the symbolic link, then call symlink() to recreate it and make it point to the other file:
unlink(path);
symlink(name, path);

Is there any C function to get the directory permission?

I am trying to implement the ls command in C without using the system function.
Is there a C function to get the directory/file permissions, so that I can display them?
Thanks.
The stat() system call takes a filename string and returns the following structure:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* protection */
nlink_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of owner */
gid_t st_gid; /* group ID of owner */
dev_t st_rdev; /* device ID (if special file) */
off_t st_size; /* total size, in bytes */
blksize_t st_blksize; /* blocksize for filesystem I/O */
blkcnt_t st_blocks; /* number of blocks allocated */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
This works equally well on directory entries as well as files and the st_mode is the specific field you're looking for.
The <sys/stat.h> header file should contain that structure and all the definitions along with #defines and/or macros for intelligently decoding the fields (see here for a sample).
If you're interested in how it's really done, you can look at the ls source code in GNU coreutils. But only use that to educate yourself. It's GPL so you can't just grab it for your own purposes and, if this is homework, your educator will almost certainly fail you if you turn in something that looks too similar to this.
Look into stat(). Sounds like you're on a Linux or POSIX system, so that should be the way.
Then look at the st_mode field of the struct stat, it contains the information about protection bits, which are often collectively called a file's "mode" (as reflected by the chmod command that changes the settings).
Going from the binary bits to a textual representation like ls' is ... an interesting challenge.
The stat functions family (stat(), lstat(), fstat()).

Resources