How to make two files have the same access time using C? - c

I have two file paths; both point to a file, say 'abc.txt' and 'folder/cde.txt'
How can I make it so that abc.txt has the same access time as the other file?
I believe I can use stat() and utime() but I tried and failed.
Here's my code.
int myLink(const char *oldfile, const char *newfile)
{
int result = link(oldfile, newfile);
int ret; /* return value */
struct stat buf; /* struct to hold file stats */
ret = stat(oldfile, &buf);
if (ret != 0) {
perror("Failed:");
exit(ret);
}
struct utimbuf puttime;
puttime.modtime = buf.st_mtime;
printf("\tatime: %d\n", buf.st_mtime);
if (utime(newfile, &puttime))
perror("utime");
else
{
if (utime(extName, NULL)) /* set to current time */
perror("utime");
}
return result;
}

Assuming you have two file names, then you don't want to use the link() system call. If for some reason you do want to link the files, you need to worry about it return value (which will be an error if the second file already exists; you have to unlink() the new file name first). Once the files are linked, they are two references to the same inode and inevitably have the same access time.
You then need to decide whether you want the first file to have the modification time of the second file or vice versa, or whether you want them both to have the same other access time (such as now, or some time in the past - or future!).
Assuming you want the second file's access time to be the same as the first file's access time (but the modification time of the second file to be unchanged), then you need to:
Collect the times of the first file.
Collect the times of the second file.
Create an appropriate struct utimbuf structure.
Call utime().
Alternatively, for steps 3 and 4, you create an appropriate array of struct timeval, and use utimes().
I'm intrigued (even puzzled) to see that the struct stat in POSIX 2008 has no members st_mtime, st_atime, and st_ctime (of type time_t) any more: instead, it has st_mtim, st_atim and st_ctim of type struct timeval. These allow for sub-second resolution on the timestamps. I strongly suspect that the older members are typically present for reasons of backwards compatibility, if nothing else.
I am going to assume st_mtime and st_atime and utime() (and no linking). This leads to revised code:
int myLink(const char *oldfile, const char *newfile)
{
struct stat buf1;
struct stat buf2;
if (stat(oldfile, &buf1) != 0)
return(-1);
if (stat(newfile, &buf2) != 0)
return(-1);
struct utimbuf puttime;
puttime.modtime = buf2.st_mtime;
puttime.acttime = buf1.st_atime;
return utime(newfile, &puttime);
}
If you want diagnostic printing, you can easily add it. In general, library functions should not exit the program; it makes them unusable. Diagnostic printing is also problematic - maybe you should not be writing to stderr, for example.

If you create a hard link (using the link syscall) then there is only one file, and it has only one modification time and access time. It can't be different from itself.
$ touch A
$ ln A B
$ ls -l A B
-rw-r--r-- 1 user group 0 Nov 2 0:00 A
-rw-r--r-- 1 user group 0 Nov 2 0:00 B
$ sleep 60
$ touch B
-rw-r--r-- 1 user group 0 Nov 2 0:01 A
-rw-r--r-- 1 user group 0 Nov 2 0:01 B
Note in the above example, there is only one file. Both A and B are the same file. The ln command just calls link.

You are using modtime instead of atime and you're assigning a timespec to a time_t. You probably want:
puttime.actime = buf.st_atim.tv_sec;
^^^^^^

Related

How to list first level directories only in C?

In a terminal I can call ls -d */. Now I want a c program to do that for me, like this:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main( void )
{
int status;
char *args[] = { "/bin/ls", "-l", NULL };
if ( fork() == 0 )
execv( args[0], args );
else
wait( &status );
return 0;
}
This will ls -l everything. However, when I am trying:
char *args[] = { "/bin/ls", "-d", "*/", NULL };
I will get a runtime error:
ls: */: No such file or directory
The lowest-level way to do this is with the same Linux system calls ls uses.
So look at the output of strace -efile,getdents ls:
execve("/bin/ls", ["ls"], [/* 72 vars */]) = 0
...
openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
getdents(3, /* 23 entries */, 32768) = 840
getdents(3, /* 0 entries */, 32768) = 0
...
getdents is a Linux-specific system call. The man page says that it's used under the hood by libc's readdir(3) POSIX API function.
The lowest-level portable way (portable to POSIX systems), is to use the libc functions to open a directory and read the entries. POSIX doesn't specify the exact system call interface, unlike for non-directory files.
These functions:
DIR *opendir(const char *name);
struct dirent *readdir(DIR *dirp);
can be used like this:
// print all directories, and symlinks to directories, in the CWD.
// like sh -c 'ls -1UF -d */' (single-column output, no sorting, append a / to dir names)
// tested and works on Linux, with / without working d_type
#define _GNU_SOURCE // includes _BSD_SOURCE for DT_UNKNOWN etc.
#include <dirent.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
DIR *dirhandle = opendir("."); // POSIX doesn't require this to be a plain file descriptor. Linux uses open(".", O_DIRECTORY); to implement this
//^Todo: error check
struct dirent *de;
while(de = readdir(dirhandle)) { // NULL means end of directory
_Bool is_dir;
#ifdef _DIRENT_HAVE_D_TYPE
if (de->d_type != DT_UNKNOWN && de->d_type != DT_LNK) {
// don't have to stat if we have d_type info, unless it's a symlink (since we stat, not lstat)
is_dir = (de->d_type == DT_DIR);
} else
#endif
{ // the only method if d_type isn't available,
// otherwise this is a fallback for FSes where the kernel leaves it DT_UNKNOWN.
struct stat stbuf;
// stat follows symlinks, lstat doesn't.
stat(de->d_name, &stbuf); // TODO: error check
is_dir = S_ISDIR(stbuf.st_mode);
}
if (is_dir) {
printf("%s/\n", de->d_name);
}
}
}
There's also a fully compilable example of reading directory entries and printing file info in the Linux stat(3posix) man page. (not the Linux stat(2) man page; it has a different example).
The man page for readdir(3) says the Linux declaration of struct dirent is:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
d_type is either DT_UNKNOWN, in which case you need to stat to learn anything about whether the directory entry is itself a directory. Or it can be DT_DIR or something else, in which case you can be sure it is or isn't a directory without having to stat it.
Some filesystems, like EXT4 I think, and very recent XFS (with the new metadata version), keep type info in the directory, so it can be returned without having to load the inode from disk. This is a huge speedup for find -name: it doesn't have to stat anything to recurse through subdirs. But for filesystems that don't do this, d_type will always be DT_UNKNOWN, because filling it in would require reading all the inodes (which might not even be loaded from disk).
Sometimes you're just matching on filenames, and don't need type info, so it would be bad if the kernel spent a lot of extra CPU time (or especially I/O time) filling in d_type when it's not cheap. d_type is just a performance shortcut; you always need a fallback (except maybe when writing for an embedded system where you know what FS you're using and that it always fills in d_type, and that you have some way to detect the breakage when someone in the future tries to use this code on another FS type.)
Unfortunately, all solutions based on shell expansion are limited by the maximum command line length. Which varies (run true | xargs --show-limits to find out); on my system, it is about two megabytes. Yes, many will argue that it suffices -- as did Bill Gates on 640 kilobytes, once.
(When running certain parallel simulations on non-shared filesystems, I do occasionally have tens of thousands of files in the same directory, during the collection phase. Yes, I could do that differently, but that happens to be the easiest and most robust way to collect the data. Very few POSIX utilities are actually silly enough to assume "X is sufficient for everybody".)
Fortunately, there are several solutions. One is to use find instead:
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d");
You can also format the output as you wish, not depending on locale:
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\n'");
If you want to sort the output, use \0 as the separator (since filenames are allowed to contain newlines), and -t= for sort to use \0 as the separator, too. tr will convert them to newlines for you:
system("/usr/bin/find . -mindepth 1 -maxdepth 1 -type d -printf '%p\0' | sort -t= | tr -s '\0' '\n'");
If you want the names in an array, use glob() function instead.
Finally, as I like to harp every now and then, one can use the POSIX nftw() function to implement this internally:
#define _GNU_SOURCE
#include <stdio.h>
#include <ftw.h>
#define NUM_FDS 17
int myfunc(const char *path,
const struct stat *fileinfo,
int typeflag,
struct FTW *ftwinfo)
{
const char *file = path + ftwinfo->base;
const int depth = ftwinfo->level;
/* We are only interested in first-level directories.
Note that depth==0 is the directory itself specified as a parameter.
*/
if (depth != 1 || (typeflag != FTW_D && typeflag != FTW_DNR))
return 0;
/* Don't list names starting with a . */
if (file[0] != '.')
printf("%s/\n", path);
/* Do not recurse. */
return FTW_SKIP_SUBTREE;
}
and the nftw() call to use the above is obviously something like
if (nftw(".", myfunc, NUM_FDS, FTW_ACTIONRETVAL)) {
/* An error occurred. */
}
The only "issue" in using nftw() is to choose a good number of file descriptors the function may use (NUM_FDS). POSIX says a process must always be able to have at least 20 open file descriptors. If we subtract the standard ones (input, output, and error), that leaves 17. The above is unlikely to use more than 3, though.
You can find the actual limit using sysconf(_SC_OPEN_MAX), and subtracting the number of descriptors your process may use at the same time. In current Linux systems, it is typically limited to 1024 per process.
The good thing is, as long as that number is at least 4 or 5 or so, it only affects the performance: it just determines how deep nftw() can go in the directory tree structure, before it has to use workarounds.
If you want to create a test directory with lots of subdirectories, use something like the following Bash:
mkdir lots-of-subdirs
cd lots-of-subdirs
for ((i=0; i<100000; i++)); do mkdir directory-$i-has-a-long-name-since-command-line-length-is-limited ; done
On my system, running
ls -d */
in that directory yields bash: /bin/ls: Argument list too long error, while the find command and the nftw() based program all run just fine.
You also cannot remove the directories using rmdir directory-*/ for the same reason. Use
find . -name 'directory-*' -type d -print0 | xargs -r0 rmdir
instead. Or just remove the entire directory and subdirectories,
cd ..
rm -rf lots-of-subdirs
Just call system. Globs on Unixes are expanded by the shell. system will give you a shell.
You can avoid the whole fork-exec thing by doing the glob(3) yourself:
int ec;
glob_t gbuf;
if(0==(ec=glob("*/", 0, NULL, &gbuf))){
char **p = gbuf.gl_pathv;
if(p){
while(*p)
printf("%s\n", *p++);
}
}else{
/*handle glob error*/
}
You could pass the results to a spawned ls, but there's hardly a point in doing that.
(If you do want to do fork and exec, you should start with a template that does proper error checking -- each of those calls may fail.)
If you are looking for a simple way to get a list of folders into your program, I'd rather suggest the spawnless way, not calling an external program, and use the standard POSIX opendir/readdir functions.
It's almost as short as your program, but has several additional advantages:
you get to pick folders and files at will by checking the d_type
you can elect to early discard system entries and (semi)hidden entries by testing the first character of the name for a .
you can immediately print out the result, or store it in memory for later use
you can do additional operations on the list in memory, such as sorting and removing other entries that don't need to be included.
#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
int main( void )
{
DIR *dirp;
struct dirent *dp;
dirp = opendir(".");
while ((dp = readdir(dirp)) != NULL)
{
if (dp->d_type & DT_DIR)
{
/* exclude common system entries and (semi)hidden names */
if (dp->d_name[0] != '.')
printf ("%s\n", dp->d_name);
}
}
closedir(dirp);
return 0;
}
Another less low-level approach, with system():
#include <stdlib.h>
int main(void)
{
system("/bin/ls -d */");
return 0;
}
Notice with system(), you don't need to fork(). However, I recall that we should avoid using system() when possible!
As Nomimal Animal said, this will fail when the number of subdirectories is too big! See his answer for more...

How to detect when one file is modified inside a symbolic link directory in Linux

I have a symbolic link to one directory like this
root#beaglebone:/sys/class/drm#
lrwxrwxrwx 1 root root 0 Sat Jan 1 00:00:01 2000 card0-HDMI-A-1 -> /sys/devices/ocp.3/4830e000.lcdc/drm/card0/card0-HDMI-A-1
How can I detect/watch when one file is modified inside the real path (/sys/devices/ocp.3/4830e000.lcdc/drm/card0/card0-HDMI-A-1) which the symbolic link (/sys/class/drm/card0-HDMI-A-1) points to.
(I prefer a C program to do this).
Thanks much.
The command you are looking for is stat. stat retrieves data about a file (in *nix, a directory is a kind of file). When used on a symbolic link, stat will return data on what the link points to, not the link itself. stat populates a struct stat, whose st_mtime member is the time of the last modification, which for a directory, will update when its contents change.
struct stat file_info;
if ( stat ( "/sys/class/drm/card0-HDMI-A-1", &file_info ) == 0 ) {
/* stat succeeded, file_info.st_mtime is the real directory's mod time */
} else {
/* stat failed for some reason. consult the man page for info about error codes */
}

Programmatically read all the processes status from /proc

I want to save all of the running processes' status from the /proc folder in a file. After reading some questions and answers here I think I should use the pstatus struct to determine which fields I want to save (correct me if I'm wrong?), but I don't know how I can efficiently loop through all of the running processes.
In Linux process status is saved in /proc/PID/status pseudo-file and represented in textual form (other OS have completely different structure of their procfs):
$ grep State /proc/self/status
State: R (running)
So you need a "parser" for that file:
void print_status(long tgid) {
char path[40], line[100], *p;
FILE* statusf;
snprintf(path, 40, "/proc/%ld/status", tgid);
statusf = fopen(path, "r");
if(!statusf)
return;
while(fgets(line, 100, statusf)) {
if(strncmp(line, "State:", 6) != 0)
continue;
// Ignore "State:" and whitespace
p = line + 7;
while(isspace(*p)) ++p;
printf("%6d %s", tgid, p);
break;
}
fclose(statusf);
}
To read all processes you have to use opendir()/readdir()/closedir() and open only directories that have numerical characters (other are sysctl variables, etc.):
DIR* proc = opendir("/proc");
struct dirent* ent;
long tgid;
if(proc == NULL) {
perror("opendir(/proc)");
return 1;
}
while(ent = readdir(proc)) {
if(!isdigit(*ent->d_name))
continue;
tgid = strtol(ent->d_name, NULL, 10);
print_status(tgid);
}
closedir(proc);
Alternatively, you may use procps tools which already implemented it.
This snippet below invokes two C programs that do just that:
find /proc -maxdepth 2 -wholename '/proc/[0-9]*/status' | xargs cat
It's an old question, but still definitely a relevant one.
If you don't want to mess with parsing procfs yourself, you should definitely check out pfs. It a library for parsing most of procfs written in C++. (Disclaimer: I'm the author of the library)
On a Linux system, every task (process or thread) has an entry under the /procfs directory.
When enumerating the directories under /procfs you'll get a directory for each running processes.
Under each directory, you can find two files: stat and status, that include the current process status.
The possible statuses are described (almost correctly) under man proc(5):
(3) state %c
One of the following characters, indicating process state:
R Running
S Sleeping in an interruptible wait
D Waiting in uninterruptible disk sleep
Z Zombie
T Stopped (on a signal) or (before Linux 2.6.33) trace stopped
t Tracing stop (Linux 2.6.33 onward)
W Paging (only before Linux 2.6.0)
X Dead (from Linux 2.6.0 onward)
x Dead (Linux 2.6.33 to 3.13 only)
K Wakekill (Linux 2.6.33 to 3.13 only)
W Waking (Linux 2.6.33 to 3.13 only)
P Parked (Linux 3.9 to 3.13 only)
This is almost correct, because there's an additional possible value that is missing from this list:
I Idle
If you want to get the value from stat, the simplest way to go is probably use as fopen & fscanf. The format is intimately described under man proc(5) as well. Note: Just be carefull with the comm value format. They say it's %s, but it's actually much more complicated, since it might include spaces or any other character, it might screw up your parser (one more reason to use a mature parsing library).
If you want to get the value from status, you should probably open the file using std::ifstream or something like that and use std::getline till the lines starts with Status:, and then extract the value you want.

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().)

Traversing file system according to a given root place by using threads by using C for unix

I wanna traverse inside the file system by using threads and processes.My program has to assume the first parameter is either given as "-p" which offers a multi-process application or "-t" which runs in a multi-threaded way. The second parameter is the
pathname of a file or directory. If my program gets the path of a file, it should print out the size of the file in bytes. If my program gets the path of a directory, it should, in the same way, print out the directory name, then process all the entries in the
directory except the directory itself and the parent directory. If my program is given a directory, it must display the entire hierarchy rooted at the specified directory. I wrote something but I got stuck in.I can not improve my code.Please help me.
My code is as following:
include
include
include
include
include
include
include
int funcThread(DIR *D);
int main(int argc, char * argv[])
{
pthread_t thread[100];
DIR *dirPointer;
struct stat object_file;
struct dirent *object_dir;
int counter;
if(opendir(argv[1])==NULL)
{
printf("\n\nERROR !\n\n Please enter -p or -t \n\n");
return 0;
}
if((dirPointer=opendir(argv[1]))=="-t")
{
if ((object_dir = opendir(argv[2])) == NULL)
{
printf("\n\nERROR !\n\nPlease enter the third argument\n\n");
return 0;.
}
else
{
counter=0;
while ((object_dir = readdir(object_dir)) != NULL)
{
pthread_create(&thread[counter],NULL,funcThread,(void *) object_dir);
counter++;
}
}
}
return 0;
}
int funcThread(DIR *dPtr)
{
DIR *ptr;
struct stat oFile;
struct dirent *oDir;
int num;
if(ptr=readdir(dPtr)==NULL)
rewinddir(ptr);
if(S_ISDIR(oFile.st_mode))
{
ptr=readdir(dPtr);
printf("\t%s\n",ptr);
return funcThread(ptr);
}
else
{
while(ptr=readdir(dPtr)!=NULL)
{
printf("\n%s\n",oDir->d_name);
stat(oDir->d_name,&oFile);
printf("\n%f\n",oFile.st_size);
}
rewinddir(ptr);
}
}
This line:
if((dirPointer=opendir(argv[1]))=="-t")
dirPointer is a pointer DIR* so how can it be equal to a literal string pointer?
I spotted a few errors:
Why are you using opendir() to check your arguments? You should use something like strcmp for that.
You're passing struct dirent* to funcThread() but funcThread() takes a DIR*.
You're using oFile on funcThread() before you initialize it (by calling stat()).
What is the purpose of calling rewinddir()? I guess you're blindly trying to get readdir() to work with a struct dirent*.
You're using oDir but it's never initialized.
You're calling printf() from multiple threads with no means to synchronize the output so it would be completelly out of order or garbled.
I suggest you read and understand the documentation of all those functions before using them (google "posix function_name") and get familiar with the basics of C. And before bringing threads into the equation try to get it working on a single threaded program. Also you won't see an improvement in performance by using that many threads unless you have close to that many cores, it will actually decrease performance and increase resource usage.
if(ptr=readdir(dPtr)==NULL){}
The = operator has lower precedence than ==
[this error is repeated several times]

Resources