extracting digits from octal number in C - c

Im trying to get the file permissions for a file or directory using the function stat(). I can get the correct information, such as; st_nlinks is for number of hard links and st_mode gives the mode of the file, which is what I am looking for. But the value stores in st_mode is an octal number. How do I now extract just the owner permissions.
For example the st_mode might store 42755 which means the owner has read write and execution permissions, but I don't know how to get extract the 7 from the number. If this is confusing maybe my code below will clarify things.
CODE:
DIR *dirp;
struct dirent *dp;
struct stat buf;
dirp = opendir(".");
while ((dp = readdir(dirp)) != NULL){
stat(dp->d_name, &buf);
//now here I have the octal number for the file permissions
//If I put a print statement here like so:
printf(">> %o %s\n", buf.st_mode, dp->d_name);
}
So some of you may see that I am trying to do what ls -l does on a Unix system. So instead of printing out the octal number for the mode I want to convert it to something like:
drwxr-xr-x for the value stored in st_mode: 42755
My professor recommended using a mask and perform a bitwise operation on it. I understand what he means but I tried something like:
mode_t owner = 0000100 & st_mode;
But when I print out owner I get the value of 100.
printf(">> owner permission: %o\n", owner);
OUTPUT:
owner permission: 100
So I am confused on how to do this. Does anyone know how to solve this problem?
By the way in case anyone is wondering I use mode_t as the type for owner because according to the man page for stat (man 2 stat) the member variable st_mode of the stat structure is of type mode_t. I figure this is just like a long int or something.

Use the macros defined in sys/stat.h to resolve the mode bits.
Refer to:
http://www.johnloomis.org/ece537/notes/Files/Examples/ls2.html
function mode_to_letters() for implementation details.

You should consider using defined macros rather than trying to "parse" permissions manually. Let's say you wish you get the write permission for the file owner user, that's could be checked like this:
int wpo = buff.st_mode & S_IWUSR;
if (wpo) {
printf("Ower has write permission");
} else {
printf("Ower doesn't have write permission");
}
You will find more useful macros in documentation: http://pubs.opengroup.org/onlinepubs/009695399/basedefs/sys/stat.h.html

The mask must be 0700:
111 000 000
To get owner rights rwx

Related

How to get octal chmod from st_mode

Hi I have a similar question to this post How to get octal chmod format from stat() in c but I dont have any reputation so I cant comment on it. I was wondering what value would statchmod get if the file had permission drwxrw-r-- and is that value in decimal or octal?
struct stat buf;
stat(filename, &buf);
int statchmod = buf.st_mode;
I was also wondering what number
statchmod & 0777
outputs and again is it in decimal or octal? Should it output 0764?
EDIT: Thanks, I think I have a better understanding now. Still not clear on statchmod though. Is it in bits So would
statchmod & 511
output 500?

Determining the filetype of a file in C

I am trying to figure out the file type of a file, without using external libs or the "file" command.
I have viewed a number of posts and threads, and they point to using the stat() function (unix man stat) and playing with the "st_mode" from the stat struct.
But I have no idea how to do this, nor am I able to find a good example of doing it.
For example the program takes in a file F, I want to be able to read F similar to the program below and give similar output. And the filetype of F is a PDF, but it does not have the extension on it.
FURTHER EXAMPLE: If I have foo.pdf, but I changed the extension to *.png (foo.png) I can pass my program "foo.png" and say it is infact a .pdf file.
When a file is created, it makes a "magic number", example with a PDF, the magic number of PDF files start with "%PDF" (hex 25 50 44 46)."
How can I use the magic number to figure out the filetype.
I understand some type of table will need to be made at my end, to support files. And I am only doing a small handful <10.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void errorInput()
{
fprintf(stderr, "\nYou have received this message due to an error. \n");
fprintf(stderr, "Please type 'filetype <file>' to properly execute the program.\n");
fprintf(stderr, "Thank you and have a fine day! \n\n");
exit(0);
}
int main(int argc, char *argv[])
{
char command[128];
if (argc == 2)
{
strcpy(command, "file ");
strcat(command, argv[1]);
system(command);
}
else
{
errorInput();
}
return 0;
}
Thank You in advance!
Like Jonathon Reinhart Pointed, don't try to reinvent the wheel use libmagic:
#include <stdio.h>
#include <magic.h>
int main(void) {
struct magic_set *magic = magic_open(MAGIC_MIME|MAGIC_CHECK);
magic_load(magic,NULL);
printf("Output1: '%s'\n",magic_file(magic,"ValgrindOut.xml"));
printf("Output2: '%s'\n",magic_file(magic,"program"));
printf("Output3: '%s'\n",magic_file(magic,"Chapter9.pdf"));
printf("Output4: '%s'\n",magic_file(magic,"test.txt"));
printf("Output5: '%s'\n",magic_file(magic,"linux-3.17.tar.xz"));
printf("Output6: '%s'\n",magic_file(magic,"gcc-5.2.0.tar.gz"));
printf("Output7: '%s'\n",magic_file(magic,"/home/michi"));
return 0;
}
Compile:
gcc -o program program.c -lmagic
Output:
Output1: 'application/xml; charset=us-ascii'
Output2: 'application/x-executable; charset=binary'
Output3: 'application/pdf; charset=binary'
Output4: 'text/plain; charset=utf-8'
Output5: 'application/x-xz; charset=binary'
Output6: 'application/gzip; charset=binary'
Output7: 'inode/directory; charset=binary'
First, you need to include sys/stat.h
Next, you need to declare a struct stat in your code:
struct stat s
Next, you pass a pointer to your stat structure along with the file/object name:
returnval = stat("filename", &s);
Check the return value, you'll get < 0 on error. If no error the object/file exists, we can use a macro function to determine the file type:
if (S_ISREG(s.st_mode))
/* Regular text file... */
else if (S_ISDIR(s.st_mode))
/* Is a directory.... */
I suggest you have a look at the man page (man 3 stat) and it will give you all of the types that st_type may potentially be (it can be used to identify files, directories, block devices, sym links, etc)
Another very useful member of the stat struct is st_size which gives you a files size in bytes.
ETA - the stat() system call won't tell you if a file is a PDF or anything like that - normally we'd use the extension, if there is no extension and you're trying to identify specific file formats then stat() won't be of much use to you.
Most files usually will have a portion called as Header/MetaData. It is in this portion/segments of the file which will contain details about the file it self.Also, these Headers/MetaData Segments will also contain the Signature to identify the file type. But be aware most of these Signatures will be in an Hex Signature format
Example
PDF Signature - 25 50 44 46(In Hex) or %PDF
JPEG Signature - Start FF D8 and end of file FF D9
So, Basically you need to open the file in a binary format and parse the file structure and compare it to see if it matches with any one of the file types you define in your program.Like suppose you wanna check if it's pdf file then you need to first open the file in binary mode then scan the file till you get the bytcode/hex code which matches the bytcode/hex code of a pdf file. Use the C fopen() function in binary mode i.e "rb".
Or you can open the file normally without binary mode like this,
unsigned int data;
data=fgetc(pfile);
You might want to look into this for further details,
Magic Number
File Signatures

In a C program in Linux OS, how to check if a user has read permission on a file?

The function would be something like this.
int GetFilePermission(char* pcUsername, char* pcFilePath)
{
/*return TRUE if 'pcUsername' has read permission on file 'pcFilePath'.*/
}
I don't want to use stat(). Since it would be little bit long. I have to check file's permissions, it's owners and compare them in different combinations. Is there any short and simple way/trick of doing this?
Please help. Thanks in advance.
Using the access function we can get the user having a permission. See the man page of access.
int access(const char *pathname, int mode);
If you stat function, you getting all information about that file. In access we have these four only. R_OK, W_OK, X_OK and F_OK. Using this we can get easily. Return value is zero if success.
R_OK = read permission
W_OK = Write permission
X_OK = Execute permission
F_OK = file is existing.
You can use stat
Prototype for stat
#include <sys/stat.h>
int stat(const char *restrict path, struct stat *restrict buf);

Determining if two file paths point to same file under Linux / C?

Under Linux, I have two file paths A and B:
const char* A = ...;
const char* B = ...;
I now want to determine, should I open(2) them both...
int fda = open(A, ...);
int fdb = open(B, ...);
...will I get two filehandles open to the same file in the filesystem?
To determine this I thought of stat(2):
struct stat
{
dev_t st_dev;
ino_t st_ino;
...
}
Something like (pseudo-code):
bool IsSameFile(const char* sA, const char* sB)
{
stat A = stat(sA);
stat B = stat(sB);
return A.st_dev == B.st_dev && A.st_ino == B.st_ino;
}
Are there any cases where A and B are the same file but IsSameFile would return false?
Are there any cases where A and B are different files but IsSameFile would return true?
Is there a better way to do what I'm trying to do?
Your program will work fine in all the cases because A.st_ino will return the inode number of the files in your system. Since inode number is unique your program will correctly identify whether the two files opened are same or not.
You can also check the value of A.st_mode to find out whether the file is a symbolic link.
It depends on why exactly you want to avoid opening the same file twice. Your solution is usually the correct one, but there are some situations where files should be considered the same if they have the same absolute path but not if they are links to the same inode. In that case you need to convert the paths to absolute paths and compare them ... see Getting absolute path of a file
You also need to decide whether you consider a symlink to a file equivalent to the file or another symlink to it. For inode equivalence, that determines whether to use stat or lstat. For path equivalence, it determines whether you can use realpath or if you need to get the absolute path without following symlinks.

How to get file information similar to "ls -la" using C?

I am using ar.h for the defining the struct. I was wondering on how I would go about getting information about a file and putting it into those specified variables in the struct.
struct ar_hdr {
char ar_name[16]; /* name of this member */
char ar_date[12]; /* file mtime */
char ar_uid[6]; /* owner uid; printed as decimal */
char ar_gid[6]; /* owner gid; printed as decimal */
char ar_mode[8]; /* file mode, printed as octal */
char ar_size[10]; /* file size, printed as decimal */
char ar_fmag[2]; /* should contain ARFMAG */
};
Using the struct defined above, how would I put get the information from the file from ls -la
-rw-rw----. 1 clean-unix upg40883 368 Oct 29 15:17 testar
?
You're looking for stat(2,3p).
In order to emulate the behavior of ls -la you need a combination of readdir and stat. Do a man 3 readdir and a man 2 stat to get information on how to use them.
Capturing the output of ls -la is possible, but not such a good idea. People might expect that of a shell script, but not a C or C++ program. It's even sort of the wrong thing to do in Python or perl if you can help it.
You will have to construct your structure yourself from the data available to you. strftime can be used for formatting the time in a manner you like.
For collecting data about a single file into an archive header entry, the primary answer is stat(); in other contexts (such as ls -la), you might also need to use lstat() and readlink(). (Beware: readlink() does not null terminate its return string!)
With ls -la, you would probably use the opendir() family of functions (readdir() and closedir() too) to read the contents of a directory.
If you needed to handle a recursive search, then you'd be looking at nftw(). (There's also a less capable ftw(), but you'd probably be better off using nftw().)

Resources