Get a file's creation time with GLib - file

it can't be that hard but I just don't get it: I want to retrieve a file's creation time (not modification time) from within GLib (I am using Vala at the moment, but C or any other language with GLib Binding would do). I have this code:
File file = File.new_for_commandline_arg(args[1]);
FileInfo info = file.query_info("*", 0);
uint64 t = info.get_attribute_uint64(FileAttribute.TIME_CREATED);
stdout.printf("%llu\n", t);
which prints out 0 (indicating "invalid" according to the docs) on any file. I know there is a info.get_modification_date() available, which works as expected, but I need the time of the file's creation.
Google did not give me any results, so I hope someone here could give me a clue in the right direction.
Thanks a lot in advance!

If you are running your code on Linux, it's simply because that information is not available. You can check with g_file_info_has_attribute if a given attribute is actually available for a GFileInfo.

Related

Renaming & moving my file based on the size is not always working in c. Why?

I have an application, written in C, which generates various data parameters that I am logging into a text file named debug_log.txt. Whenever this log file reaches 1 MB, I am renaming the filename with timestamp ex debug_log_20200106_133000.txt & moving it in same directory. I am then reopening debug_log.txt to log new parameters.
if(stat("/home/log/debug_log.txt", &statFiledbg) == 0)
{
if(statFiledbg.st_size >= 1048576) // 1MB
{
current_time = time(0);
strftime(time_buffer, sizeof(time_buffer), "%Y%m%d_%H-%M-%S", gmtime(&current_time));
sprintf(strSysCmddbg, "mv /home/log/debug_log.txt /home/log/debug_log%s.txt", time_buffer);
system(strSysCmddbg);
fp_dbglog = freopen("/home/log/debug_log.txt", "w", fp_dbglog);
}
}
The code works most of the time until it doesn't. After running the application for couple days, I see that debug_log.txt grows beyond 1 MB while the last moved & renamed log file is empty.
What could be the reason?
Use the rename function from the C standard library (in stdio.h) and check errno if it failed to know the exact reason why it is failing.
When working with files, and I/O in general, there are many, many things that can go wrong.
One of my senior developer in the company told me so. Is there anything wrong with using system()?
Yes: it is unnecessary (C and POSIX provide you with a function for basic usages like this), nonportable (it assumes you are in a system that has a "mv"), slower (it needs to spawn another process) and wrong for many use cases (eg. here there is no way to know what exactly failed unless you save the textual output of mv).
See questions and answers like Moving a file on Linux in C for an in-depth explanation.

tcl "open" command not working when replacing Tcl_Filesystem with a duplicate

I'm trying to write a custom filesystem for Tcl using the Tclapi (it's work related, won't go into details), but I'm stuck trying to figure out why this is not working.
In this code segment I'm getting the original/native Tcl_Filesystem, copying over all its contents (function pointers) to my_fs, and then calling Tcl_FSRegister on my_fs. Very simple, thought it should work.
// global scope
const Tcl_Filesystem *ori_fs;
Tcl_Filesystem *my_fs;
...
// in Init
// Get the original Tcl_Filesystem.
Tcl_Obj *root_obj = Tcl_NewStringObj("/", -1);
Tcl_IncrRefCount(root_obj);
ori_fs = Tcl_FSGetFileSystemForPath(root_obj);
Tcl_DecrRefCount(root_obj);
// create a duplicate of the original Tcl_Filesystem struct.
my_fs = malloc(sizeof(Tcl_Filesystem));
memmove(my_fs, ori_fs, ori_fs->structureLength);
int ret = Tcl_FSRegister((ClientData)1, my_fs);
if (ret == TCL_ERROR) {
...
When I ran
load <path to .so>/my_fs[info sharedlibextension]
# sanity check
puts [pwd]
set fp [open test.txt]
however, I get this
<my current directory>
while executing
"open test.txt"
invoked from within
"set fp [open test.txt]"
(file "test.tcl" line 3)
Notice how "puts [pwd]" works but not "open test.txt" ?
Replacing "my_fs" with "ori_fs" in the call to Tcl_FSRegister seems to work...
I've already spent far too much time trying to figure this out. I would appreciate if anyone could help me with this!
The native filesystem is special. In particular, there's some places where its identity is used directly: for example, it's the only FS that can have temporary files made on it, it's assumed to own the roots, and it is handled specially in path management. (Well, according to where in the source code there are direct references to the Tcl internal variable tclNativeFilesystem, which isn't something you can cheat at. It's also possibly in read-only memory, so you can't hack around this.)
For most sane uses of a Tcl virtual filesystem, this doesn't matter. Temp files have to be native because you may well be passing them to the OS (e.g., for loading libraries or running programs that were inside the VFS; with these, they have to be copied out or the OS will think “what are you talking about?!”) and you put the things that you are mounting somewhere other than the native root. So long as you're not trying to use a VFS as a security measure (not recommended; there are safe interpreters for that as they offer a stronger sandboxing solution) it shouldn't be a problem as you can just make your code know that it needs to work below a particular location to get things done. (FWIW, it's a bad idea to cd anyway, except in response to user requests, since it changes the meaning of user-supplied relative paths, so good code handles “make everything relative to a defined location” from the start.)

How can I tell if I have permissions to delete a file with Qt5 without actually trying to delete it?

Question
I am looking for something that would fulfil the expected semantics of an imagined isRemovable() method in the QFile class.
In QFile reference there is a permissions() method mentioned that returns a set of flags QFileDevice::Permission wich basically corresponds to file permissions. There is also isReadable() and isWritable() but how can I in a relatively portable way know with certainty that I would be able to remove (delete) a file without actually trying?
Answer
Short answers with short and simple source-code are preferred.
You can remove a file if you have permissions to write both to a file and to it's containing directory. So, the solution (which I've tested on Centos Linux) will be:
QFileInfo fileInfo(filepath);
QFileInfo dirInfo(fileInfo.path());
bool isRemovable = fileInfo.isWritable() && dirInfo.isWritable();

what is the meaning of stable in zfile_stable - CZMQ

CZMQ man page for zfile explains zfile_stable as:
// Check if file is 'stable'
CZMQ_EXPORT bool zfile_stable (const char *filename);
What is the meaning of stable? when a file is said to be stable?
The use case here is using files to signal between processes. The example application is FileMQ, which publishes new files out to subscribers. But there's no obvious way to know when a file has been "created"; the two solutions I know are to create a second "signal" file, which is rather clumsy, or to use this "has the file been modified in the last second" algorithm.
Let's say you're copying photos into one directory, and a parallel process is detecting new photos and uploading them to a server. On a large photo, the modified date will keep changing until it's stable. Then, it's safe to upload the photo.
Hope that helps.
The definition of stable in this context is if a file more than 1s old.
See https://github.com/zeromq/czmq/blob/master/src/zfile.c#L115

Retrieving Global Variable Values from Command Line

In one particular project, we're trying to embed version information into shared object files. We'd like to be able to use some standard linux tool to parse the shared object to determine the version for automated testing.
Currently I have "const int plugin_version = 14;". I can use 'nm' and 'objdump' and verify that it's there:
00000000000dcfbc r plugin_version
I can't, however, seem to be able to get the value of that variable easily from command line. I figured there'd be a POSIX tool for showing the initialized values for globals. I have contemplated using a format for the variable as the information itself, ie, plugin_version_14, but that seems like a huge hack. Embedding the information in the filename unfortunately is NOT an option. Any other suggestions welcome.
You could embed it as a string
"MAGIC MARKER STRING VERSION: 4.56 END OF MAGIC" then just look for "MAGIC MARKER STRING" in the file and extract the version information that comes after it.
if you make it a standard, you could easily make command line tool to find these embeded strings on all your software.
if you require it also to be an int, a little macro magic will construct both the int and magic string to make sure they are never out of synch.
There's a couple of options I think.
My first instinct is to make sure the version information lives in its own section in the ELF file. You can use objdump -s -j name of section /bin/whatever.
This rather relies on objdump being available of course.
Alternatively you can do what Keith suggested, and just use 'strings', along with a magical marker string. This feels a little hackish, but should work quite well.
Finally, why don't you just add a --version command line option? You can then store the version information however you like, and trivially retrieve it using the one tool which is certain to be installed on any system which has your software.
A terrible hack that I've used in the past is to embed the version information in a variable name, so nm will show:
00000000000dcfbc r plugin_version_14
Why not writing your own tool to get that version in C/C++ ? You could Use dlopen, then dlsym to get the symbol and print its value to standard output. This way you also verify if the symbol is already there. It looks like 20 ~ 30 lines of code to me and about 20 minutes of your life :)
I know that the question is about command line, but writing such a tool yourself should be easy (especially if such a command line tool does not exist).
If the binary is not stripped, you could use gdb to print the variable. (I just tried to script gdb, but it seems to refuse work if stdin is not a tty, maybe expect will do the job ? )
If you can accept using python, this might help:
import struct
import sys
import subprocess
if __name__ == '__main__':
so = sys.argv[1]
sym = sys.argv[2]
addr = subprocess.check_output('nm %s | grep %s' % (so, sym), shell=True)
addr = int(addr.split()[0], 16)
so_file = open(so)
so_file.seek(addr)
data = so_file.read(4)
print struct.unpack('#i', data)[0]
Disclaimer: This script doesn't do any error checking (if you like it I'm sure you can come up with some ;)). It also assumes you're reading a 4-byte native int value.
$ cat global.c
const int plugin_version = 14;
$ python readsym.py global.so plugin_version
14

Resources