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()).
Related
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
I have a function that opens file then read theses files, with the standard open() et read() functions. I use the errno variables for all possible errors such as permission denied or no such file or directory, but when I use open on a directory it don't return a error it simply open it and try to read it.
So how can I get an error message when I give open a directory ?
Directory is also a file (In terms of Unix/Linux). So generally you won't get an error. You can use stat or fstat function for tracking of ordinary or special files.
When you use either stat or fstat, you need to declare a struct stat variable like struct stat var. The stat structure has a member called st_mode which has the information of what kind of file it is.
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 */
};
Directory also a file in Unix*, if you want to avoid to open a directory by open(), you may need to check the file type. As #nayabbashasayed say,you can use the stat to check the file type and more info.
Here is an example code to check the type by stat:
const char *filePath;
struct stat fileStatBuf;
if(stat(filePath,&fileStatBuf) == -1){
perror("stat");
exit(1);
}
/*
*You can use switch to check all
*the types you want, now i just use
*if to check one.
*/
if((fileStatBuf.st_mode & S_IFMT) == S_IFDIR){
printf("This type is directory\n");
}
Hope that can help you.
I don't wanted to use anything else as read and write, I found that the error is returned at using read() not by open()
Suppose that I have file name or an open file decriptor for a text file that resides on a storage device (hard disk, usb flash, dvd, etc.). How can I get block size of that device from file name/descriptor in Linux programmatically in C. I know about ioctl system call, but it accepts an open descriptor for device special file, not an open descriptor of a file on that device.
For example I have a file name "/home/hrant/file1.txt" (or an open file descriptor on that file) that is on some storage device (like /dev/sda1). I don't know on which device the file is. How to get block size of that device to read contents of file "/home/hrant/file1.txt" in blocks.
As fstat() man page says:
int fstat(int fildes, struct stat *buf);
int stat(const char *path, struct stat *buf);
The stat() function obtains information about the file pointed to by path. Read, write or execute permission of the named file is not required, but all directories listed in the path name leading to the file must be searchable.
The fstat() obtains the same information about an open file known by the file descriptor fildes.
The buf argument is a pointer to a stat structure as defined by and into which information is placed concerning the file.
the stat structure is defined as:
struct stat {
dev_t st_dev; /* device inode resides on */
ino_t st_ino; /* inode's number */
mode_t st_mode; /* inode protection mode */
nlink_t st_nlink; /* number of hard links to the file */
uid_t st_uid; /* user-id of owner */
gid_t st_gid; /* group-id of owner */
dev_t st_rdev; /* device type, for special file inode */
struct timespec st_atimespec; /* time of last access */
struct timespec st_mtimespec; /* time of last data modification */
struct timespec st_ctimespec; /* time of last file status change */
off_t st_size; /* file size, in bytes */
quad_t st_blocks; /* blocks allocated for file */
u_long st_blksize;/* optimal file sys I/O ops blocksize */
};
I hope it helps you.
In linux, when stat() is used with broken link files, it fails with -1. So I used lstat() which succeeded.
For the same case in windows, _stat() fails with broken shortcuts, but there is no _lstat() in windows. Please help to find the alternative for lstat() in windows.
The accepted answer does not provide a full stat equivalent. The stat struct is defined as
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 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 */
};
but GetFileAttributes.. does not provide any owner information (it returns data in a WIN32_FIND_DATA object). If you need that owner information, it looks like you can use GetSecurityInfo [1].
[1] https://msdn.microsoft.com/en-us/library/windows/desktop/aa446629%28v=vs.85%29.aspx
GetFileAttributes or GetFileAttributesEx probably (if I understood stat and lstat right). Quoting from the docs:
Symbolic link behavior—If the path points to a symbolic link, the function returns attributes for the symbolic link.
hey _stat() or stat() works fine on broken shortcuts as well. Thats the reason,there is no alternative like lstat(UNIX) in windows.
Where in Unix, stat() fails with broken links, so lstat is provided to fix the problem.
Thank you all for your help.
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);