How to get file creation date in Linux? - c

I am working with batches of files that contain information about the same object at the different times of its life, and the only way to order them is by creation date.
I was using this:
//char* buffer has the name of file
struct stat buf;
FILE *tf;
tf = fopen(buffer,"r");
//check handle
fstat(tf, &buf);
fclose(tf);
pMyObj->lastchanged=buf.st_mtime;
But that does not seems to work.
What am I doing wrong? Are there other, more reliable/simple ways to get file creation date under Linux?

The nearest approximation to 'creation date' is the st_ctime member in the struct stat, but that actually records the last time the inode changed. If you create the file and never modify its size or permissions, that works as a creation time. Otherwise, there is no record of when the file was created, at least in standard Unix systems.
For your purposes, sort by st_mtime...or get the files named with a timestamp in the name.
Note that if you are on Darwin (Mac OS X), the creation time is available. From the man page for stat(2):
However, when the macro _DARWIN_FEATURE_64_BIT_INODE is defined, the stat structure will now be defined as:
struct stat { /* when _DARWIN_FEATURE_64_BIT_INODE is defined */
dev_t st_dev; /* ID of device containing file */
mode_t st_mode; /* Mode of file (see below) */
nlink_t st_nlink; /* Number of hard links */
ino_t st_ino; /* File serial number */
uid_t st_uid; /* User ID of the file */
gid_t st_gid; /* Group ID of the file */
dev_t st_rdev; /* Device ID */
struct timespec st_atimespec; /* time of last access */
struct timespec st_mtimespec; /* time of last data modification */
struct timespec st_ctimespec; /* time of last status change */
struct timespec st_birthtimespec; /* time of file creation(birth) */
off_t st_size; /* file size, in bytes */
blkcnt_t st_blocks; /* blocks allocated for file */
blksize_t st_blksize; /* optimal blocksize for I/O */
uint32_t st_flags; /* user defined flags for file */
uint32_t st_gen; /* file generation number */
int32_t st_lspare; /* RESERVED: DO NOT USE! */
int64_t st_qspare[2]; /* RESERVED: DO NOT USE! */
};
Note the st_birthtimespec field. Note, too, that all the times are in struct timespec values, so there is sub-second timing (tv_nsec gives nanosecond resolution). POSIX 2008 <sys/stat.h> requires the struct timespec time keeping on the standard times; Darwin follows that.

fstat works on file descriptors, not FILE structures. The simplest version:
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#ifdef HAVE_ST_BIRTHTIME
#define birthtime(x) x.st_birthtime
#else
#define birthtime(x) x.st_ctime
#endif
int main(int argc, char *argv[])
{
struct stat st;
size_t i;
for( i=1; i<argc; i++ )
{
if( stat(argv[i], &st) != 0 )
perror(argv[i]);
printf("%i\n", birthtime(st));
}
return 0;
}
You will need to figure out if your system has st_birthtime in its stat structure by inspecting sys/stat.h or using some kind of autoconf construct.

File creation time is not stored anywhere, you can only retrieve one of the following:
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 */
Your code should give you the last modification time, however. Note: you can use stat() instead of fstat() without opening the file (stat() takes the file name as param).

To get the file creation date in linux, I use the following method
root#sathishkumar# cat << _eof > test.txt
> Hello
> This is my test file
> _eof
root#sathishkumar# cat test.txt
Hello
This is my test file
root#sathishkumar# ls -i test.txt
2097517 test.txt
root#sathishkumar# debugfs -R 'stat <2097517>' /dev/sda5
Inode: 2097517 Type: regular Mode: 0664 Flags: 0x80000
Generation: 4245143992 Version: 0x00000000:00000001
User: 1000 Group: 1000 Size: 27
File ACL: 0 Directory ACL: 0
Links: 1 Blockcount: 8
Fragment: Address: 0 Number: 0 Size: 0
ctime: 0x50ea6d84:4826cc94 -- Mon Jan 7 12:09:00 2013
atime: 0x50ea6d8e:75ed8a04 -- Mon Jan 7 12:09:10 2013
mtime: 0x50ea6d84:4826cc94 -- Mon Jan 7 12:09:00 2013
crtime: 0x5056d493:bbabf49c -- Mon Sep 17 13:13:15 2012
Size of extra inode fields: 28
EXTENTS:
(0):8421789
atime: Last time file was opened or executed
ctime: Time the inode information was updated. ctime also gets updated when file is modified
mtime: Last modified time
crtime: File creation time

For recent Linux versions, there is xstat which includes btime. https://unix.stackexchange.com/a/407305/103120

Related

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

How to get last modified time of a file in OS X/ C?

I have the following code:
struct stat info;
stat("/Users/john/test.txt", &info);
printf("%s\n", ctime(&info.st_mtimespec));
in which I am trying to get the last modified time of the file as displayed in the ls -l command in the format:
Jan 29 19:39
Unfortunately, above code doesn't work.I get the following error message on xcode:
Conflicting types for ctime
How can I fix it ? If there any alternative approaches to get the time in format mentioned, please do mention.
Checking on struct stat's declaration you'll see that st_mtimespec must be st_mtime.
Then, basing on this question, I rearranged your code like this:
struct stat info;
struct tm* tm_info;
char buffer[16];
stat("/Users/john/test.txt", &info);
tm_info = localtime(&info.st_mtime);
strftime(buffer, sizeof(buffer), "%b %d %H:%M", tm_info);
printf("%s\n", buffer);
Hope it helps.
I believe this is what you are looking for:
#include <sys/stat.h>
#include <time.h>
int main(int argc, char *argv[])
{
struct stat info;
stat("sample.txt", &info);
printf("%.12s\n", 4+ctime(&info.st_mtimespec));
return 0;
}
Output( same as time field of ls -l):
Feb 4 00:43
(This was for a random file on my computer).
does your code have:
#include <time.h>
also, the ctime() function expects the passed parameter to be a POINTER to a time_t.
Here is the struct pointed to by the stat() function:
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 */
};
Notice that none of the fields are a st_mtimespec
perhaps you meant st_mtime
Note: your running OS-X and I'm running linux, but the OS-X should have the very same definitions of field names.

Function that returns file size?

int filesize(FILE * handle)
{
int filesize;
int old_pointer = ftell(handle);
fseek(handle, 0, SEEK_END);
filesize = ftell(handle);
fseek(handle, old_pointer, SEEK_SET);
return filesize;
}
Is this a good way for a function to return the size of a file?
It is one way to do it, as long as your files aren't too big (which, for a 32-bit system or Windows 64-bit, means not more than 2 GiB). It has the merit of more or less working on any platform. Of course, ftell() returns a long, not an int (so on a 64-bit non-Windows system, the files it can report on are much bigger, as long as you fix your code appropriately). However, requiring four function calls is a trifle expensive.
The POSIX alternatives are stat(), lstat() and fstat().
There will be analogues in the Windows API.
I'd personally use a function from the stat family, like so. Also, note that int may be too small for the return value (especially on 32-bit systems); off_t is guaranteed to work.
off_t filesize(FILE *handle) {
struct stat statbuf;
if (fstat(fileno(handle), &statbuf) != 0) {
// handle an error
} else {
return statbuf.st_size;
}
}
Note also that this can be easily tweaked to work for files that aren't open yet by using standard stat() instead of fstat().
You could use stat() or fstat() if you were on *nix.
Use stat:
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
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 */
};

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);

How can I get exact total space of a drive using C language program running on Linux?

How can I get exact total space of a drive using C language program running on Linux? I dont want to use shell script. Any suggestions?
statfs/statfs64
#include <sys/vfs.h> /* or <sys/statfs.h> */
int statfs(const char *path, struct statfs *buf);
int fstatfs(int fd, struct statfs *buf);
From the man page:
The function statfs() returns information about a mounted file system.
path is the pathname of any file within the mounted file system.
buf is a pointer to a statfs structure defined approximately as follows:
struct statfs {
long f_type; /* type of file system (see below) */
long f_bsize; /* optimal transfer block size */
long f_blocks; /* total data blocks in file system */
long f_bfree; /* free blocks in fs */
long f_bavail; /* free blocks avail to non-superuser */
long f_files; /* total file nodes in file system */
long f_ffree; /* free file nodes in fs */
fsid_t f_fsid; /* file system id */
long f_namelen; /* maximum length of filenames */
};
You can use it like this:
struct statfs buf;
statfs("/", &buf);

Resources