How do I write file modification dates programmatically in POSIX? - c

I would like to touch my files from C code to modify their access date. This does not seem to work:
struct stat fileSt;
lstat(path, &fileSt);
fileSt.st_mtime = time(NULL);
Thank you for help.

utimes() is probably how to do it. utime() is obsolete.
Things like this are trivial to determine using tools like strace.
strace touch -t 01010911 xxx
.
.
open("xxx", O_WRONLY|O_NONBLOCK|O_CREAT|O_NOCTTY|O_LARGEFILE, 0666) = 0
utimes("/proc/self/fd/0", {1230829860, 0}) = 0

I think you want utime(2). That should be enough:
utime(filename, NULL);
The docs say:
int utime(const char *filename, const struct utimbuf *times);
[...]
The utime() system call changes the access and modification times of the
inode specified by filename to the actime and modtime fields of times
respectively.
If times is NULL, then the access and modification times of the file are
set to the current time.

The old utime() and utimes() are OK for many use-cases, but to update atime & mtime with nanosecond resolution, which you need on modern systems, use:
utimensat(0, path, NULL, 0);
This is very useful in combination with newer stat() which returns a struct timespec st_mtim field in struct stat with nanosecond resolution as well.

I think you need to look at the utime()/utimes() system call. Not at my normal computer so I can't look up the details I'm afraid.

Related

posix_spawn pipe dmesg to python script

I've got several USB to 422 adapters in my test system. I've used FTProg to give each adapter a specific name: Sensor1, Sensor2, etc. They will all be plugged in at power on. I don't want to hard code each adapter to a specific ttyUSBx. I want the drivers to figure out which tty it needs to use. I'm developing in C for a linux system. My first thought was to something like this in my startup code.
system("dmesg | find_usb.py");
The python script would find the devices since each one has a unique Product Description. Then using the usb tree to associate each device with its ttyUSBx. The script would then create /tmp/USBDevs which would just be a simple device:tty pairing that would be easy for the C code to search.
I've been told...DoN't UsE sYsTeM...use posix_spawn(). But I'm having problems getting the output of dmesg piped to my python script. This isn't working
char *my_args[] = {"dmesg", "|", "find_usb.py", NULL};
pid_t pid;
int status;
status = posix_spawn(&pid, "/bin/dmesg", NULL, NULL, my_args, NULL);
if(status == 0){
if(waitpid(pid, &status, 0) != -1);{
printf("posix_spawn exited: %i", status);
}
I've been trying to figure out how to do this with posix_spawn_file_actions(), but I'm not allowed to hit the peak of the 'Ballmer Curve' at work.
Thanks in advance
Instead of using /dev/ttyUSB* devices, write udev rules to generate named symlinks to the devices. For a brief how-to, see here. Basically, you'll have an udev rule for each device, ending with say SYMLINK+=Sensor-name, and in your program, use /dev/Sensor-name for each sensor. (I do recommend using Sensor- prefix, noting the initial Capital letter, as all device names are currently lowercase. This avoids any clashes with existing devices.)
These symlinks will then only exist when the matching device is plugged in, and will point to the correct device (/dev/ttyUSB* in this case). When the device is removed, udev automagically deletes the symlink also. Just make sure your udev rule identifies the device precisely (not just vendor:device, but serial number also). I'd expect the rule to look something like
SUBSYSTEM=="tty", ATTRS{idVendor}=="VVVV", ATTRS{idProduct}=="PPPP", ATTRS{serial}=="SSSSSSSS", SYMLINK+="Sensor-name"
where VVVV is the USB Vendor ID (four hexadecimal digits), PPPP is the USB Product ID (four hexadecimal digits), and SSSSSSSS is the serial number string. You can see these values using e.g. udevadm info -a -n /dev/ttyUSB* when the device is plugged in.
If you still insist on parsing dmesg output, using your own script is a good idea.
You could use FILE *handle = popen("dmesg | find_usb.py", "r"); and read from handle like it was a file. When complete, close the handle using int exitstatus = pclose(handle);. See man popen and man pclose for the details, and man 2 wait for the WIFEXITED(), WEXITSTATUS(), WIFSIGNALED(), WTERMSIG() macros you'll need to use to examine exitstatus (although in your case, I suppose you can just ignore any errors).
If you do want to use posix_spawn() (or roughly equivalently, fork() and execvp()), you'd need to set up at least one pipe (to read the output of the spawned command) – two if you spawn/fork+exec both dmesg and your Python script –, and that gets a bit more complicated. See man pipe for details on that. Personally, I would rewrite the Python script so that it executes dmesg itself internally, and only outputs the device name(s). With posix_spawn(), you'd init a posix_file_actions_t, with three actions: _adddup2() to duplicate the write end of the pipe to STDOUT_FILENO, and two _addclose()s to close both ends of the pipe. However, I myself prefer to use fork() and exec() instead, somewhat similar to the example by Glärbo in this answer.

Dart - How can I get the creationTime of a File?

I need to get the creationTime of a File in my Flutter project but all I have from a File object is lastModified() and lastAccessed(), no trace of a method to get the DateTime of creation.
I see that in Java it is possible: https://stackoverflow.com/a/2724009/3997782
and also in Swift: https://stackoverflow.com/a/6428757/3997782
I could use the Flutter MethodChannel function to get that but I would like to know if there a native Dart way to get it.
How to get the local file information, such as file creation time
Not all platforms does have a concept of file creation time. E.g. Linux does not for all file systems and the general stat() call does not provide that information.
That does not mean you cannot access what seems to be creation time. But you should not necessarily trust its value which are also documented in the Java API:
Returns the creation time. The creation time is the time that the file was created.
If the file system implementation does not support a time stamp to indicate the time when the file was created then this method returns an implementation specific default value, typically the last-modified-time or a FileTime representing the epoch (1970-01-01T00:00:00Z).
https://docs.oracle.com/javase/7/docs/api/java/nio/file/attribute/BasicFileAttributes.html#creationTime()
Dart does have a similar API if you use the FileStat class which have this property:
DateTime changed
The time of the last change to the data or metadata of the file system object.
On Windows platforms, this is instead the file creation time.
https://api.dart.dev/stable/2.7.2/dart-io/FileStat/changed.html
But the data for FileStat is documented to come from the POSIX stat() system call which does not have a concept of creation timestamp of files but has 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 */
Which maps to the three timestamps you can get from FileStat:
import "dart:io";
main() {
final stat = FileStat.statSync("test.dart");
print('Accessed: ${stat.accessed}');
print('Modified: ${stat.modified}');
print('Changed: ${stat.changed}');
}
But as you can see on Linux with XFS it will return the same value for changed and modified:
[julemand101#beta ~]$ dart test.dart
Accessed: 2020-04-07 18:19:20.404
Modified: 2020-04-07 18:19:19.020
Changed: 2020-04-07 18:19:19.020
You can get a different changed time if you e.g. update inode information:
[julemand101#beta ~]$ chmod +x test.dart
[julemand101#beta ~]$ dart test.dart
Accessed: 2020-04-07 18:19:42.341
Modified: 2020-04-07 18:19:19.020
Changed: 2020-04-07 18:19:39.397
Which makes sense since the st_ctime is documented as:
The field st_ctime is changed by writing or by setting inode information (i.e., owner, group, link count, mode, etc.).
https://linux.die.net/man/2/stat
So in short, you should try and see what happens for iOS and Android when using FileStat. But in short, it is difficult to write a platform independent API which gives access to differences at each platform. Especially for a platform like Linux where it is up to each file system if a feature exists or not.

Detecting that a mount point has noexec set before calling exec() on a file?

My program calls exec() on a binary that has been written to a directory specified by the user. If the directory resides in a tree mounted with "noexec", the exec() fails with EACCES.
Instead of failing the exec(), I would like to be able to figure out if a directory was mounted with noexec, but none of fcntl(), stat() or mount() return this info (from reading the manpages). Looking at the kernel source for the exec system call, it looks like this info is stored in the metadata of the inode, and I don't see this info being returned from any system call.
673 struct nameidata nd;
(..)
677 err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ|FMODE_EXEC);
678 file = ERR_PTR(err);
(..)
682 file = ERR_PTR(-EACCES);
683 if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
684 S_ISREG(inode->i_mode)) {
Does anyone know of a way to do this?
Thanks.
You can use statvfs()
struct statvfs st;
inr rc = statvfs("/mnt/foo", &st);
if (rc == -1)
error();
if (st.f_flag & ST_NOEXEC) {
//no exec flags was set
}
Did you consider reading /proc/mounts then determining which file system your program binary resides on, perhaps using statfs(2) and/or realpath(3)?
But you always should care about, and handle, the failure of execve(2) and related exec functions, which can fail for a variety of reasons.
There are many ways execve can fail, and some of them are not easily reproducible; likewise for the failure of fork or any other syscall.
I would either leave and report the EACCESS error (of execve), or, if you absolutely want to catch & explain more the noexec mount option, do the more complex thing (statfs and/or realpath and scanning of /proc/mounts or /proc/self/mounts) after such an EACCESS failure.
There is no much point in testing a binary path before execve-ing it ... just report the error after...

Find the oldest file within a directory in C on Windows

I am working on a C project and I am trying to find the oldest file within a directory so that that once the oldest file has been found, it is then deleted. I can not find anything on how to do this in C using windows, have found ways to do it in Linux but I need a version for Windows.
Basically you scan the directory, same as in Linux (but you could check out the Boost library also).
The data about time and date are already available in the directory scan structure
HANDLE fh;
FILETIME oldest = {-1U, -1U};
// Buffer to hold file name
oldestFile = malloc(MAX_PATH);
fd = malloc(sizeof(WIN32_FIND_DATA));
if (INVALID_HANDLE_VALUE == (fh = FindFirstFile(directory_name, fd)))
// Signal error, free memory, (and return an error code?)
// OK to proceed
do
{
if(fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue;
//
if ((fd->ftCreationTime.dwHighDateTime < oldest.dwHighDateTime)
|| (fd->ftCreationTime.dwHighDateTime == oldest.dwHighDateTime
&& fd->ftCreationTime.dwLowDateTime < oldest.dwLowDateTime))
{
oldest.dwHighDateTime = fd->ftCreationTime.dwHighDateTime; // ftLastAccessTime? ftLastWriteTime?
oldest.dwLowDateTime = fd ->ft CreationTime.dwLowDateTime;
strncpy(oldestFile, MAX_PATH, fd->cFileName);
}
} while(FindNextFile(fh, fd));
FindClose(fh);
free(fd); fd = NULL;
You'll want to use the FindFirstFile/FindNextFile combination on Windows to get the files in the directory. You can then either use stat as you would in Linux, or GetFileAttributesEx to check the dates.
Since windows is POSIX compliant, you should be able to read a directory and do a stat() on the files.
You could use the GetFileAttributesEx() function which populates a WIN32_FILE_ATTRIBUTE_DATA struct which has three time related members:
ftCreationTime
ftLastAccessTime
ftLastWriteTime
You can compare whichever of these is more relevant and keep track of the oldest file found during iteration. Once iteration is over, delete it using DeleteFile(). The time members are of type FILETIME and can be compared using CompareFileTime().
Or use the GetFileTime() to obtain the relevant time attribute, as commented by BeyondSora.
For finding the details of file in windows you'll have to refer to File Allocation Table which includes all the details about the files.
Check here for the coding part to read FAT

How to get inode count of a filesystem on Solaris/Unix?

I was invoking the following command and reading the outpup df -F ufs -o i. It worked fine initially but then started to fail for the reason reported and explained here http://wesunsolve.net/bugid/id/6795242.
Although the solution suggested on the above link might work but it is ugly and I want a permanent solution. So, really looking for c api on Solaris/Unix that would give me the total and available number of inodes given a filesystem.
Sample/Example is much appreciated.
The statvfs system call can be used to retrieve file system statistics including the number of total inodes and the number of free inodes. Use the system call to retrieve a statvfs structure and then inspect the f_files and f_ffree fields to determine the number of inodes and the number of free inodes, respectively.
Example:
#include <statvfs.h>
struct statvfs buffer;
int status;
fsfilcnt_t total_inodes;
fsfilcnt_t free_inodes;
...
status = statvfs("/home/betaylor/file_in_filesystem", &buffer);
total_inodes = buffer.f_files;
free_inodes = buffer.f_ffree;
...
What you want is statvfs -- see the man page on the Solaris web site.

Resources