C code to Sync Flash Drives - c

Just as a learning experience, I'm trying to code the following problems in C.
If two flash drives are inserted each having a folder (say,
Course_Notes), then they get synced. That is, data is copied from one
to the other and if there a file already exists, then the newer one is
retained.
I would do this in bash by:
#!/bin/bash
while $1
do
cp -ur /media/PD_1/Course_Notes /media/PD_2/Course_Notes
cp -r /media/PD_2/Course_Notes /media/PD_1/Course_Notes
done
How do I do this in C without too many system calls ?

In the real world, you'd probably use something like rsync for this.
You're probably looking for the stat() family of functions to get size and modification date, along with opendir()/readdir()/closedir() for directory listings. The standard way for copying a file itself is to open the source and destination, and write to the latter what you read from the former with the usual read and write functions.
Note also that the source code for GNU and BSD versions of the standard UNIX utilites, such as cp, is freely available. (likewise for rsync) You may want to read some of that source code to see what you may have missed in your own approach.

Since this is a programming Q&A site, you would use usual programming tools (instead of rewriting them yourself).
This sounds like a perfect application for a Distributed Version Control System. Some of the most popular choices today are Git and Mercurial.

Related

Readlink not finding C files (MSYS)

A while back I asked a question about this subject and "solved" it by using Cygwin instead with its XWin utility, but I've come back to this issue again since the Xwin utility does not use my GPU and creates a severe bottleneck in simulations as a result. MinGW/MSYS on the other hand DOES use my GPU for rendering, which is a huge help, but there are some rough areas that need smoothing over, specifically with readlink.
Basically, the src/makefile for rebound (https://github.com/hannorein/rebound) says this:
PREDEF+= -D$(shell basename `readlink gravity.c` '.c' | tr '[a-z]' '[A-Z]')
PREDEF+= -D$(shell basename `readlink boundaries.c` '.c' | tr '[a-z]' '[A-Z]')
PREDEF+= -D$(shell basename `readlink collisions.c` '.c' | tr '[a-z]' '[A-Z]')
If my understanding is correct, this is supposed to find which version of gravity, boundaries and collisions I specified, and adds that to PREDEFS so the compiler uses the right versions of gravity, boundaries and collisions. However, it does not seem to work in MSYS. What it ends up spitting out for predefs is this:
-DOPENGL -D.C -D.C -D.C
Obviously it did not get anything back from the code above. This results in a macronames must be identifiers error, of course. I can work around this by adding any of the special options in between readlink and the filename, like -f, for instance, but then it only spits out
-DOPENGL -DGRAVITY -DBOUNDARIES -DCOLLISIONS
Which is not right because it should have extra bits, like so:
-DOPENGL -DGRAVITY_DIRECT -DBOUNDARIES_OPEN -DCOLLISIONS_NONE
Now, if I don't want any special gravity, boundaries or collisions, the workaround is okay, but only because (I'm guessing) it defaults to those if there's nothing special specified after each macroname. But if I DO want something special, like the more efficient gravity tree code, or actual collisions, the shortened name resulting from the workaround will not help it find anything, and so it causes errors in compiling as certain functions it needed from the special files obviously are missing.
And so I'm pretty stuck at the moment. I would like very much to be able to use other codes than the defaults, but MSYS is acting funny with the readlink and not finding the right stuff. As I said, it worked fine in an X windows style compiler. I feel like there must be some library I'm missing or some hidden syntax disconnect I'm overlooking that needs to be accounted for between XWin and non-Xwin compiling, but I can't find anything.
Here's an example of the links it should be reading (at least I think this is what is being read, I'm still learning makefiles):
ln -fs gravity_tree.c ../../src/gravity.c
ln -fs boundaries_open.c ../../src/boundaries.c
ln -fs collisions_none.c ../../src/collisions.c
If anyone can tell me why this would work on an Xwin command line but not MSYS, I'd greatly appreciate it.
Why on earth do you expect readlink to work in MSYS? Where did you even get whatever readlink.exe is being invoked, (if that is what is being executed)? There is no readlink command in a standard MSYS installation. Perhaps you discovered it in MinGW.org's msys-coreutils-ext package? If this is the case, you should note the comment within the description of that package, (as seen via MinGW.org's mingw-get installer):
The msys-coreutils-bin subpackage contains those applications that were historically part of the standard MSYS installation. The associated msys-coreutils-ext subpackage contains the rest of the coreutils applications that have been (nominally) ported to MSYS -- usually these are less often used, and are not guaranteed to work: e.g. 'su.exe', 'chroot.exe' and 'mkfifo.exe' are known to be broken.
and, it seems that we may add readlink.exe to that list of "known to be broken" applications.
It may also be worth noting that readlink is not among the list of supporting tools, which a GNU Coding Standards conforming application is permitted to invoke from either its configure script, or its makefile. Thus, there is little incentive for the MinGW.org developers, (who maintain MSYS), to address the issue of making readlink.exe work, (although patches from an independent developer, with such an incentive, would be welcomed).
As a final qualification, and as one comment on the question notes, ln -s creates copies of files; it does not create symbolic links. How could it? MSYS itself dates from an era when windows didn't support symbolic links ... indeed, even today its support for them is flaky. At the time when MSYS was published, either copying the files, or creating NTFS hard links, was the best compromise MSYS could offer, in the situation where a script invoked ln -s. Consequently, it would become incumbent upon any developer submitting patches to make readlink.exe work, to also address the issue of updating ln.exe, such that it could create the symbolic links, (in an OS version dependent fashion), which readlink.exe would then read.
I'm sorry if this isn't the answer you hoped for, but unless someone devotes some effort into updating MSYS, so that it can make use of the (unreliable) symbolic link feature in more recent windows versions, then you need to find a different approach; current MSYS does not support symbolic links, even if the underlying OS now does.

Moving a file on Linux in C

Platform: Debian Wheezy 3.2.0-4-686-pae
Complier: GCC (Debian 4.7.2-5) 4.7.2 (Code::Blocks)
I want to move a file from one location to another. Nothing complex like moving to different drives or to different file systems. I know the "standard" way to do this would be simply copying the file and then removing the original. But I want some way of preserving the file's ownership, mode, last access/modification, etc. . I am assuming that I will have to copy the file and then edit the new file's ownership, mode, etc. afterwards but I have no idea how to do this.
The usual way to move a file in C is to use rename(2), which sometimes fail.
If you cannot use the rename(2) syscall (e.g. because source and target are on different filesystems), you have to query the size, permission and other metadata of the source file with stat(2); copy the data looping on read(2), write(2) (using a buffer of several kilobytes), open(2), close(2) and the metadata using chmod(2), chown(2), utime(2). You might also care about copying attributes using getxattr(2), setxattr(2), listxattr(2). You could also in some cases use sendfile(2), as commented by David C. Rankin.
And if the source and target are on different filesystems, there is no way to make the move atomic and avoid race conditions (So using rename(2) is preferable when possible, because it is atomic according to its man page). The source file can always be modified (by another process) during the move operations...
So a practical way to move files is to first try doing a rename(2), and if that fails with EXDEV (when oldpath and newpath are not on the same mounted filesystem), then you need to copy bytes and metadata. Several libraries provide functions doing that, e.g. Qt QFile::rename.
Read Advanced Linux Programming - and see syscalls(2) - for more (and also try to strace some mv command to understand what it is doing). That book is freely and legally downloadable (so you could find several copies on the Web).
The /bin/mv command (see mv(1)) is part of GNU coreutils which is free software. You could either study its source code, or use strace(1) to understand what that command does (in terms of syscalls(2)). In some open source Unix shells like sash or busybox, mv might be a shell builtin. See also path_resolution(7) and glob(7).
There are subtle corner cases (imagine another process or pthread doing some file operations on the same filesystem, directory, or files). Read some operating system textbook for more.
Using a mix of snprintf(3), system(3), mv(1) could be tricky if the file name contains weird characters such as tab or or newlines, or starts with an initial -. See errno(3).
If the original and new location for the file are on the same filesystem then a "move" is conceptually identical to a "rename."
#include <stdio.h>
int rename (const char *oldname, const char *newname)

why are there so many versions of header files in my system?

I learned to program with Pascal in high school, and more recently I decided to get out of the sandbox and try to figure out how my computer actually works. So I installed ubuntu on my iMac (i686) and started learning C, which seemed like a good way to get "under the hood."
One of the basic things I'm trying to figure out is where the kernel ends and the standard libraries begin. A book told me that the linux system calls (which I understand to be the interface between the kernel and the libraries) could be found in the header file unistd.h, so this seemed like a good place to start. But when I tried to find the header on my system (using locate unistd.h), I got this result:
/usr/include/unistd.h
/usr/include/asm-generic/unistd.h
/usr/include/i386-linux-gnu/asm/unistd.h
/usr/include/i386-linux-gnu/bits/unistd.h
/usr/include/i386-linux-gnu/sys/unistd.h
/usr/include/linux/unistd.h
/usr/lib/syslinux/com32/include/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/alpha/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/arm/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/avr32/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/blackfin/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/c6x/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/cris/include/arch-v10/arch/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/cris/include/arch-v32/arch/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/cris/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/frv/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/h8300/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/hexagon/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/ia64/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/m32r/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/m68k/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/microblaze/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/mips/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/mn10300/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/openrisc/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/parisc/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/powerpc/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/s390/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/score/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/sh/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/sparc/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/tile/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/unicore32/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/x86/include/asm/ia32_unistd.h
/usr/src/linux-headers-3.5.0-27/arch/x86/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/arch/xtensa/include/asm/unistd.h
/usr/src/linux-headers-3.5.0-27/include/asm-generic/unistd.h
/usr/src/linux-headers-3.5.0-27/include/linux/unistd.h
/usr/src/linux-headers-3.5.0-27-generic/include/linux/unistd.h
Why the heck are there so many versions of this file--and other header files--in my system? Some of them seem to be for other CPUs (like sparc), so why did ubuntu bother to install them on my computer? And how does the all of this fit with what Eric Raymond calls the SPOT rule: "every piece of knowledge must have a single, unambiguous, authoritative representation within a system." (The Art of Unix Programming, p. 91.)
Thanks in advance for any help. I'm happy to read big books if necessary.
I think these header files are directly from linux-3.5.0-27 source code. Ubuntu developers didn't know what kind of target they are dealing with. Maybe Intel x86/powerPC/ or even a mobile hand set(ARM), so they just copy all the head files and make a simple link.

Finding file type in Linux programmatically

I am trying to find the file type of a file like .pdf, .doc, .docx etc. but programmatically not using shell command. Actually i have to make an application which blocks access to files of a particular extension. I have already hooked sys_call_table in LKM and now i want that when an open/read system call is triggered then my LKM checks the file type.
I know that we have a current pointer which gives access to current process structure and we can use it to find the file name stored in dentry structure and also in Linux a file type is identified by a magic number stored in starting bytes of file. But i don't know that how to find file type and exactly where it is stored ?
Linux doesn't "store" the file type for its files (unlike Mac OS' resource fork, which I think is the most well-known platform to do this). Files are just named streams of bytes, they have no structure implied by the operating system.
Either you just tell programs which file to use (and then it Does What You Say), or programs use higher-level features to figure it out.
There are programs that re-invent this particular wheel (I'm responsible for one of those), but you can also use e.g. file(1). Of course that requires your program to parse and "understand" the textual output you'll get, which in a sense only moves the problem.
However, I don't think calling into file from kernel space is very wise, so it's probably best to re-create the test for whatever set of types you need, to keep it small.
In other words, I mean you should simply re-implement the required tests. This is quite complicated in general, so if you really need to do it for as a large a set of types as possible, it might not be a very good idea. :/
Actually i have to make an application which blocks access to files of a particular extension.
that's a flawed requirement. If you check by file extension, then you'll miss files that doesn't use the extension which is quite common in Linux since it does not use file extension.
The officially sanctioned way of detecting file type in Linux is by their magic number. The shell command file is basically just a wrapper for libmagic, so you have the option of linking to that library

Using parse_datetime from gnu c

I am developing a program for analyzing time series under gnu/linux. To analyze a time window, I want to be able to specify start/end times on the command line. Parsing dates using strptime is simple enough, however I would like to use the flexible 'natural language' format as it is used by the unix ''date'' command. There, this is done using the parse_datetime function.
I have the source of the coreutils, but would like to avoid copying over the code and all attached header files.
My question is: is there a standard library under Unix/Linux which gives access to the full power of parse_datetime().
The function you refer to is not part of any standard, nor any stock utility library. However, it is available as a semi-standalone component as part of gnulib, namely the parse-datetime module. You will need to take it and incorporate it into your program; the gnulib distribution has tools for that. Be aware that if you do this you have to GPL your entire program (this is not a big deal if the program is only for your personal use -- the GPL's requirements only kick in when you start giving the compiled program to other people).
A possible alternative is g_date_set_parse from GLib, but I can't speak to how clever it is.

Resources