How do I add permissions to my ls-al c program? - c

I am writing code to implement the ls-al command using c program and I have gotten my code to implement it without printing permissions but I want to implement the permissions as well but cant figure out how. any suggestions? my code is below
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
// Last Modified
time_t t = my_stat.st_mtime;
localtime_r(&t, &lt);
char timebuf[80];
strftime(timebuf, sizeof(timebuf), "%c", &lt);
if (pwd != 0) {
printf("%s \t %ld \t %s \t %s", pwd->pw_name, (long)my_stat.st_size, timebuf, current_directory->d_name);
printf("\n");
} else {
printf("%d \t %ld \t %s \t %s", my_stat.st_uid, (long)my_stat.st_size, timebuf, current_directory->d_name);
printf("\n");
}
}
closedir(directory);
return 0;
}
int main(int argc, char* argv[]) {
if ( argc == 1 ) {
return list_dir ( "." );
} else {
int ret = 0;
for (int i = 1; i < argc; i += 1 ) {
if ( list_dir ( argv[i] ) != 0 ) {
ret = 1;
}
}
return ret;
}
}
I have ben trying for a long time to be able to add permissions to this code but I seem to be getting stuck and am out of ideas here
the output of my code is:
kev 0 Thu Jun 20 13:39:49 2019 .
kev 0 Thu Jun 20 13:39:46 2019 ..
kev 24147 Thu Jun 20 12:24:40 2019 CMakeCache.txt
kev 0 Thu Jun 20 13:39:53 2019 CMakeFiles
kev 1426 Thu Jun 20 12:24:41 2019 cmake_install.cmake
kev 5160 Thu Jun 20 12:24:41 2019 Makefile
the expected output is:
rw-r--r-- 1 kev 0 Thu Jun 20 13:39:49 2019 .
rw-r--r-- 1 kev 0 Thu Jun 20 13:39:46 2019 ..
-rw------- 24147 Thu Jun 20 12:24:40 2019 CMakeCache.txt
rw-r--r-- kev 0 Thu Jun 20 13:39:53 2019 CMakeFiles
-rw------- kev 1426 Thu Jun 20 12:24:41 2019 cmake_install.cmake
rw-r--r-- kev 5160 Thu Jun 20 12:24:41 2019 Makefile

You will want to make use of the mode_t st_mode field of your struct stat. See stat(2):
The stat structure
All of these system calls return a stat structure, which contains the following fields:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
mode_t st_mode; /* file type and mode */
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 */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last modification */
struct timespec st_ctim; /* time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec #define st_ctime st_ctim.tv_sec };
[...]
The file type and mode (st_mode)
POSIX refers to the st_mode bits corresponding to the mask S_IFMT (see below) as the file type, the 12 bits corresponding to the mask 07777 as the file mode bits and the least significant 9 bits (0777) as the file permission
bits.
The following mask values are defined for the file type of the st_mode field:
S_IFMT 0170000 bit mask for the file type bit field
S_IFSOCK 0140000 socket
S_IFLNK 0120000 symbolic link
S_IFREG 0100000 regular file
S_IFBLK 0060000 block device
S_IFDIR 0040000 directory
S_IFCHR 0020000 character device
S_IFIFO 0010000 FIFO
[...]
The following mask values are defined for the file mode component of the st_mode field:
S_ISUID 04000 set-user-ID bit
S_ISGID 02000 set-group-ID bit (see below)
S_ISVTX 01000 sticky bit (see below)
S_IRWXU 00700 owner has read, write, and execute permission
S_IRUSR 00400 owner has read permission
S_IWUSR 00200 owner has write permission
S_IXUSR 00100 owner has execute permission
S_IRWXG 00070 group has read, write, and execute permission
S_IRGRP 00040 group has read permission
S_IWGRP 00020 group has write permission
S_IXGRP 00010 group has execute permission
S_IRWXO 00007 others (not in group) have read, write, and execute per‐
mission
S_IROTH 00004 others have read permission
S_IWOTH 00002 others have write permission
S_IXOTH 00001 others have execute permission

Related

lsetxattr returns EPERM if attempt to set a value to symlink

I am testing simple program to add timestamp to xattr.
lsetxattr system call returns error with EPERM. Is that expected behaviour?
How can I set xattr to symlink, not follow the link?
#include <sys/types.h>
#include <attr/xattr.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>
int main(int argc, char **argv){
time_t t = time(NULL);
if(lsetxattr(argv[1], "user.ts", &t, sizeof(time_t), 0) == -1){
perror(argv[1]);
}
return(0);
}
example:
> ls -l a b c
-rw-r--r-- 1 saka users 0 Feb 1 09:08 a
-rw-r--r-- 1 saka users 0 Feb 1 09:08 b
lrwxrwxrwx 1 saka users 1 Feb 1 09:08 c -> b
> ./ts a
> ./ts c
c: Operation not permitted
I tested on 3.10.0-862.14.4.el7.x86_64 with xfs or ext3.
I guess it's this:
/*
* In the user.* namespace, only regular files and directories can have
* extended attributes. For sticky directories, only the owner and
* privileged users can write attributes.
*/
And in fact, trying to set a trusted.foo attribute on a symlink with lsetxattr(2) as root works, while a user.foo fails with EPERM.

apue code chapter 4 umask.c runs abnormal

I run ./umask as the following step:
[root filedir]#
[root filedir]#ls
access bar cdpwd.c changemod.c devrdev.c filetype.c ftw8 Makefile mycd.c umask.c unlink.c zap.c
access.c cdpwd changemod devrdev filetype foo ftw8.c mycd umask unlink zap
[root filedir]#./umask
[root filedir]#ll foo bar
-rw-r--r--. 1 root root 0 7月 23 11:56 bar
-rw-rw-rw-. 1 root root 0 7月 23 11:56 foo
Here is the code umask.c
#include "apue.h"
#include <fcntl.h>
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
int
main(void)
{
umask(0);
if (creat("foo", RWRWRW) < 0)
err_sys("creat error for foo");
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (creat("bar", RWRWRW) < 0)
err_sys("creat error for bar");
exit(0);
}
as the code above,umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH),why does bar has read access for group and other?
system info :
[root filedir]#umask
0022
[root filedir]#cat /etc/redhat-release
CentOS Linux release 7.6.1810 (Core)
[root filedir]#gcc
gcc 4.8.5
Linux MiWiFi-R1CL-srv 3.10.0-957.21.3.el7.x86_64 #1 SMP Tue Jun 18 16:35:19 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
It's embarrassed for me,I make a mistake.
My friend and I share the same virtual machine,he read the book faster than me.He runs 4-12 program,which the code like the following:
#include "apue.h"
int
main(void)
{
struct stat statbuf;
/* turn on set-group-ID and turn off group-execute */
if (stat("foo", &statbuf) < 0)
err_sys("stat error for foo");
if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
err_sys("chmod error for foo");
/* set absolute mode to "rw-r--r--" */
if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
err_sys("chmod error for bar");
exit(0);
}
As for this problem ,I delete the foo and bar,and run ./umask,then everything run well.

strange system call semantics on nfs mount

I am writing a little test program for the open() function in C # open SuSE leap 42.2 x64.
Unfortunately the file being created gets -rwxrwxrwx permissions, although I hand over 0644 to the open() function after executing umask(0);
Could anyone please tell me, what I am doing wrong?
(I got the example code from an open book (link).
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char** argv) {
/* Zugriffsrechte 644 */
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
const char *new_file;
int file_descriptor;
/* Alle Zugriffsrechte der Einschraenkungsmaske erlauben */
umask(0);
/* Argument 2 der cmd line auswerten */
if (argv[1] == NULL) {
fprintf(stderr, "usage: %s datei_zum_oeffnen\n", *argv);
return EXIT_FAILURE;
}
new_file = argv[1];
file_descriptor = open(new_file, O_WRONLY|O_EXCL|O_CREAT, 0644);
/* or var mode instead of (0644) */
if (file_descriptor == -1) {
perror("Fehler bei open ");
return EXIT_FAILURE;
}
return (EXIT_SUCCESS);
}
Either way - handing over 0644 or the variable "mode" as open()'s third argument do not work as expected and the result when executing the program (as normal user) and handing in a filename is: -rwxrwxrwx and moreover: the file belongs to root:root instead of the executing user?!
What will I have to change?
Solved.
The failure was compiling it using NetBeans 8.2.
The folders and files created by NetBeans belong to root - creating the same .c-file in my home dir and compiling it there worked perfectly.
Added:
NetBeans is not running as root.
The folder which my workspace was created in is a NTFS drive, mounted during boot with user-access - but the whole drive belongs to root in the first place. I am 99% convinced that this is what led me to wrong assumptions about NetBeans creating folders and files with wrong permissions.

Implementing the ls -al command in C

As a part of an assignment from one of my classes, I have to write a program in C to duplicate the results of the ls -al command. I have read up on the necessary materials but I am still not getting the right output. Here is my code so far, its only supposed to print out the file size and the file name, but the file sizes its printing are not correct.
Code:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char* argv[])
{
DIR *mydir;
struct dirent *myfile;
struct stat mystat;
mydir = opendir(argv[1]);
while((myfile = readdir(mydir)) != NULL)
{
stat(myfile->d_name, &mystat);
printf("%d",mystat.st_size);
printf(" %s\n", myfile->d_name);
}
closedir(mydir);
}
These are my results after executing the code:
[root#localhost ~]# ./a.out Downloads
4096 ..
4096 hw22.c
4096 ankur.txt
4096 .
4096 destination.txt
Here are the correct sizes:
[root#localhost ~]# ls -al Downloads
total 20
drwxr-xr-x. 2 root root 4096 Nov 26 01:35 .
dr-xr-x---. 24 root root 4096 Nov 26 01:29 ..
-rw-r--r--. 1 root root 27 Nov 21 06:32 ankur.txt
-rw-r--r--. 1 root root 38 Nov 21 06:50 destination.txt
-rw-r--r--. 1 root root 1139 Nov 25 23:38 hw22.c
Can anyone please point out my mistake.
Thanks,
Ankur
myfile->d_name is the file name not the path, so you need to append the file name to the directory "Downloads/file.txt" first, if it's is not the working directory:
char buf[512];
while((myfile = readdir(mydir)) != NULL)
{
sprintf(buf, "%s/%s", argv[1], myfile->d_name);
stat(buf, &mystat);
....
As to why it prints 4096 that is the size of the links . and .. from the last call to stat().
Note: you should allocate a buffer large enough to hold the directory name, the file name the NULL byte and the separator, something like this
strlen(argv[1]) + NAME_MAX + 2;
This is the final code I got to work for anyone interested. It prints the correct file sizes. Credit goes to asker and mux for answering, just putting the code together. Input I got this to work for is "./main ." .
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main(int argc, char* argv[])
{
DIR *mydir;
struct dirent *myfile;
struct stat mystat;
char buf[512];
mydir = opendir(argv[1]);
while((myfile = readdir(mydir)) != NULL)
{
sprintf(buf, "%s/%s", argv[1], myfile->d_name);
stat(buf, &mystat);
printf("%zu",mystat.st_size);
printf(" %s\n", myfile->d_name);
}
closedir(mydir);
}
I believe you'll observe that if you ./a.out . you will get the behaviour you expect.
You have a slightly subtle bug, observable if you examine the return code of your call to stat(2).
The fundamental mistake: the dirents returned by readdir(2) (the myfile in your code) will have a d_name relative to mydir. Your code will stat .. first, succeed, and so mystat will contain valid data for .., then all subsequent calls to stat(2) will fail, returning -1, which you do not check for, so mystat will not be modified, and you will print the st_size for the old value, i.e. that of ...
The trouble is that when you stat("ankur.txt", &mystat), you are not working on the file "Downloads/ankur.txt". Most likely, the stat() is failing; alternatively, it is reporting on a different file.
Consequently, you need to look at whether your system supports fstatat() — new in POSIX 2008 — or arrange to prefix the name of the file with name of the directory.
or maybe just system("ls -al") will also work!

how to make holes in file to erase data by c in linux

Updated: This FALLOC_FL_PUNCH_HOLE is not originally supported by 3.0.0-17, I think I need to patch it.
I know linux have this hole feature, and I am wondering if I could make a hole in a existing file.
For specific, I have created a file named hole_test by these codes:
18 #include <stdlib.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 int main(int argc, char **argv)
26 {
27 int fd;
28 char a[7]="happy!";
30 fd = open("hole_test", O_CREAT|O_RDWR, 0666);
31 if(fd == -1)
32 printf("error, %s\n", (char *)strerror(errno));
35 // fallocate(fd, 0x02, 0,0);
36 // pwrite(fd, a, sizeof(a), 0);
37 // pwrite(fd, a, sizeof(b), 65536);
38 close(fd);
39 return 0;
40 }
firstly, I user L36 L37 to create a file. the stat hole_test shows that:
File: `hole_test'
Size: 65540 Blocks: 16 IO Block: 4096 regular file
Device: 801h/2049d Inode: 1052101 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ bxshi) Gid: ( 1000/ bxshi)
Access: 2012-04-03 23:02:35.227664608 +0800
Modify: 2012-04-03 23:02:35.227664608 +0800
Change: 2012-04-03 23:02:35.227664608 +0800
Then I use L35 and comment L36 L37 to make a hole in my file.(0x02 equals to FALLOC_FL_PUNCH_HOLE, I did not find where it is defined so just use its value)
and then, by stat hole_test, the Blocks is still 16.
File: `hole_test'
Size: 65540 Blocks: 16 IO Block: 4096 regular file
Device: 801h/2049d Inode: 1052101 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ bxshi) Gid: ( 1000/ bxshi)
Access: 2012-04-03 23:02:35.227664608 +0800
Modify: 2012-04-03 23:02:35.227664608 +0800
Change: 2012-04-03 23:02:35.227664608 +0800
I want to know if I could make new holes in this hole_test file to erase existing data?
How could I make a hole in hole_test at offset 0 to 7, in that way I think the Blocks could become 8 and the string I wrote would disappear.
Hope you guys could know what I said and give me some advice.
You use fallocate(fd, FALLOC_FL_PUNCH_HOLE, offset, len). (Supported since Linux 2.6.38) See https://lwn.net/Articles/415889/ for behind-the-scenes details and accompanying patches.
According to the man page for fallocate(2):
The FALLOC_FL_PUNCH_HOLE flag must be ORed with FALLOC_FL_KEEP_SIZE
in mode; in other words, even when punching off the end of the file,
the file size (as reported by stat(2)) does not change.
At least on ext4, if you just pass FALLOC_FL_PUNCH_HOLE, fallocate() will return Operation not supported.
Also note that:
The FALLOC_FL_* flags are
defined in glibc headers only since version 2.18.
So you may need to manually define them if you're using a supported kernel with an earlier version of libc:
// Constants are defined in glibc >= 2.18
#define FALLOC_FL_KEEP_SIZE 0x1
#define FALLOC_FL_PUNCH_HOLE 0x2

Resources