Keeping fileowner and permissions after copying file in C - c

here is my problem: In C, I create the copy of a file (with some changes) This is done trivially via fopen(), getchar and putchar.
Copying the file is fine and the outputfile itself is what I want it to be.
My problem is: I assume that I will use this program often as sudo and then the resulting file has both another owner (root) as well as different permissions (execute rights are gone).
My question is: How can I copy the owner and permissions of the original file and then write them into the new one?

Use the fstat(2) system call to obtain the details about the owner and the permissions, and the fchmod(2) and fchown(2) system calls to set them. See an example in the setfile function of the *BSD cp(1) source code.

since you use fopen():
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
//fp is your source filepointer, fdest is your dest filepointer
//fn is the new filename you're copying to
struct stat fst;
//let's say this wont fail since you already worked OK on that fp
fstat(fileno(fp),&fst);
//update to the same uid/gid
fchown(fileno(fdest),fst.st_uid,fst.st_gid);
//update the permissions
fchmod(fileno(fdest),fst.st_mode);
as a quick note, you may want to fread() and fwrite() instead of f*char()'ing

Under linux use the libc fchmod and fchown
Manpages can be found here:
http://linux.die.net/man/2/fchmod
http://linux.die.net/man/2/fchown

Related

Deleting a file using a FILE * [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can I delete a file pointed to by a FILE* in C?
I want to delete a file at the end of a C program, by which point the filename has been long forgotten. It would be nice if I could just use the FILE * to delete it directly or find the filename and then use remove()... rather than having to memorize the filename for this.
Does anybody know of any ways in which this could be achieved? I am on a Windows system, but I need to maintain portability so can't use any OS specific stuff.
nice if I could just use the FILE * to delete it directly or find the
filename and then use remove()... rather than having to memorize the
filename for this
There's no way to retrieve the file name from a FILE *. A FILE * isn't necessarily a real file; just think of popen(3) for example.
I do not know of a portable way, but there is a Linux version (which might work on other unices) and a Windows version:
Linux: a readlink() on sprintf("/proc/self/fd/%d",fd) should work
Windows: GetFileInformationByHandleEx() will give you the name as part of a struct (Search MSDN, don't have the details in my head)
E.g
#include <stdio.h>
#include <stdlib.h>
void endproc(void){
remove("removeFile.dat");
}
int main(){
atexit(endproc);
return 0;
}

function or a systemcall similar to "mountpoint" command in linux

I wanted a function or a system call similar to mountpoint command Linux.
(this command will check if given directory is a mount point or not)
I'm not aware of an actual syscall that would do that, but what you can do is compare the device numbers of the directory that you want to check and its parent. That can be done with stat. Example code (error checking omitted) :
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(void) {
struct stat mp, mp_parent;
stat("/boot", &mp);
stat("/boot/..", &mp_parent);
if (mp.st_dev != mp_parent.st_dev)
printf("/boot is a mount point.\n");
else
printf("/boot is not a mount point.\n");
return 0;
}
The need for functions like this is usually (though not always) a red flag that you're not embracing the abstractions of the system...and you should reconsider whatever-it-is-you're-doing. If there is some choice you're making in your software based on whether something is a mountpoint...consider making that alternative behavior a parameter which can be controlled via scripting. People can parameterize your program to adopt that behavior via using the native mountpoint command, or whatever else.
With that disclaimer aside, here's an implementation of mountpoint.c:
https://fossies.org/linux/sysvinit/src/mountpoint.c
...and a reference on "testing the type of a file"
http://www.aquaphoenix.com/ref/gnu_c_library/libc_160.html
Write your own app to parse /proc/mounts. Then compare your path with paths from /proc/mounts. If they are equal then path is a mount point.

Retrieving the path from a file descriptor or FILE *?

Is there a way to retrieve path information from a file descriptor or FILE pointer?
I'm aware that this data may not always be relevant/useful for case where the file descriptor is a socket, pipe, etc.
I don't believe there's any portable way, but e.g. on Linux you can call readlink on "/proc/self/fd/fileno" and the kernel will give you a path if it can, or one of various kinds of funny-looking strings if not.
If you're lucky enough to be using Mac OS X you can use the following code:
#define _DARWIN_C_SOURCE
#include <sys/fcntl.h>
.
.
.
char pathbuf[PATH_MAX];
if (fcntl(fd, F_GETPATH, pathbuf) >= 0) {
// pathbuf now contains *a* path to the open file descriptor
}
Note that the path you get back is not necessarily the one used to open the file... If there are hard links, especially, the path you get back will be a valid path to the file.
There can be one or many names for a file, so no std way.
I am not sure if there can be something OS specific.

Duplicate file descriptor with its own file offset

How can one create a new file descriptor from an existing file descriptor such that the new descriptor does not share the same internal file structure/entry in the file table? Specifically attributes such as file offset (and preferably permissions, sharing and modes) should not be shared between the new and old file descriptors.
Under both Windows and Linux, dup() will duplicate the file descriptor, but both descriptors still point to the same file structure in the process' file table. Any seeking on either descriptor will adjust the position for the other descriptors as well.
Note
I've since received answers for both Windows and Linux and adjusted the question a little too often, which has made it difficult for people to answer. I'll adjust my votes and accept the cleanest answer which covers both Windows and Linux. Apologies to all, I'm still new to the SO paradigm. Thanks for the great answers!
So basically, what you really want is to be given a file descriptor, and basically open the same file over again, to get a separate position, sharing, mode, etc. And you want to do this on Windows (where the "file descriptor" is basically a foreign object, not something used directly by the OS or the run-time library at all.
Amazingly enough, there is a way to do that, at least with MS VC++. All but two steps of it use only the Win32 API so porting to other compilers/libraries should be fairly reasonable (I think most supply versions of those two functions). Those are for converting a Unix-style file descriptor to a native Win32 file handle, and converting a native Win32 file handle back to a Unix-style file descriptor.
Convert file-descriptor to native file handle with _get_osfhandle()
Get a name for the file with GetFileInformationByHandleEx(FILE_NAME_INFO)1
Use CreateFile to open a new handle to that file
Create a file descriptor for that handle with _open_osfhandle()
Et voilĂ , we have a new file descriptor referring to the same file, but with its own permissions, position, etc.
Toward the end of your question, you make it sound like you also want the "permissions", but that doesn't seem to make any real sense -- the permissions attach to the file itself, not to how the file is opened, so opening or reopening the file has no effect on the file's permissions. If you really want to know the, you can get it with GetFileInformationByHandle, but be aware that file permissions in Windows are quite a bit different from the (traditional) file permissions in Unix. Unix has owner/group/world permissions on all files, and most systems also have ACLs (though there's more variation in how they work). Windows either has no permissions at all (e.g., files on FAT or FAT32) or else uses ACLs (e.g., files on NTFS), but nothing that's really equivalent to the traditional owner/group/world permissions most people are accustomed to on Unix.
Perhaps you're using "permissions" to refer to whether the file was open for reading, writing, or both. Getting that is considerably uglier than any of the preceding. The problem is that most of it is in the library, not Win32, so there's probably no way to do it that will be even close to portable between compilers. With MS VC++ 9.0 SP1 (not guaranteed for any other compiler) you can do this:
#include <stdio.h>
int get_perms(int fd) {
int i;
FILE * base = __iob_func();
for (i=0; i<_IOB_ENTRIES; i++)
if (base[i]._file == fd)
return base[i]._flag; // we've found our file
return 0; // file wasn't found.
}
Since this involved some spelunking, I wrote a quick test to verify that it might actually work:
#ifdef TEST
#include <io.h>
void show_perms(int perms, char const *caption) {
printf("File opened for %s\n", caption);
printf("Read permission = %d\n", (perms & _IOREAD)!=0);
printf("Write permission = %d\n", (perms & _IOWRT)!=0);
}
int main(int argc, char **argv) {
FILE *file1, *file2;
int perms1, perms2;
file1=fopen(argv[1], "w");
perms1 = get_perms(_fileno(file1));
fclose(file1);
file2=fopen(argv[1], "r");
perms2 = get_perms(_fileno(file2));
fclose(file2);
show_perms(perms1, "writing");
show_perms(perms2, "reading");
return 0;
}
#endif
And the results seem to indicate success:
File opened for writing
Read permission = 0
Write permission = 1
File opened for reading
Read permission = 1
Write permission = 0
You can then test that returned flag against _IOREAD, _IOWRT, and _IORW, which are defined in stdio.h. Despite my previous warnings, I should probably point out that I suspect (though I certainly can't guarantee) that this part of the library is fairly stable, so the real chances of major changes are probably fairly minimal.
In the other direction, however, there's basically no chance at all that it'll work with any other library. It could (but certainly isn't guaranteed to) work with the other compilers that use the MS library, such as Intel, MinGW or Comeau using MS VC++ as its back-end. Of those, I'd say the most likely to work would be Comeau, and the least likely MinGW (but that's only a guess; there's a good chance it won't work with any of them).
Requires the redistributable Win32 FileID API Library
So, I recommend reading up on this a little more. The dup() and related functions serve to create a duplicate value in the file descriptor table pointing to the same entry in the open file table. This is intended to have the same offset. If you call open(), you will create a new entry the open file table.
It doesn't make any sense to create a duplicate of a file descriptor and that new file descriptor have a different offset in the open file table (this seems to contradict what the word "duplicate" means).
I'm not sure what your question is actually. I mean, it isn't the same thing as a duplicate. You could read:
/proc/self/fd/[descriptor]
and get the string that was used to open that file descriptor; bear in mind this may provide some pitfalls, some of which you actually noted in your observation of calling open() again.
Maybe you can explain a little more and I can try to update to help.
Why don't you just open the file a second time with open() or CreateFile() on windows? This gives you all freedom of different access rights and separate offset.
This of course has the drawback that you you can not open the file exclusively, but it solves your problem very simply.

Determine UID that last modified a file in Linux?

I'm writing a program that will be monitoring select files and directories for changes. Some of the files are world writeable, some owner, some group.
What I need to do is be able to figure out the last person to modify (not just access) a file. Somehow I thought this would be simple, given that we know the inode of the file .. however I can not seem to find any way of obtaining this. I thought there was a practical way of correlating any given inode to the uid last accessing it.
I think I've squeezed google for all its going to give me on the topic.
Any help is appreciated. I'm writing the program in C.
Edit:
I need to be able to do this after the PID of whatever program modified the file is long gone.
If you are on a 2.6 kernel, you can take advantage of kernel's auditd daemon. Check this URL out. It might give you some hint on how to accomplish what you are trying to. I'm sure there is an API you could use in C.
To my knowledge, this information is not stored by any of the common filesystems, but you should by able to hook into inotify and keep an audit trail of which processes touch which files.
Okay, using straight old standard Linux with normal file systems, you're not going to be able to do it. That information isn't stored anywhere (see man lstat for what is stored.)
As #pablo suggests, you can do this with security auditing turned on. The link he notes is a good start, but the gist of it is this:
you turn on the audit daemon, which enables auditing form the kernel
you configure the rules file to capture what you want
you search the audit files for the events you want.
The difficulty here is that if you start auditing all file operations for all files, the audit is going to get big.
So what is the actual need you want to fil?
very basic , but it works:
you can easily write a little c-program that does what you want
this example retrieves the UID of file or directory or link,
just try to find the properties that you want.
compile with:
gcc -x c my-prog.c -o my-prog
then:
./my-prog /etc
a lot of other information can be obtained like this
it's not robust. but whatever, i know how to use it,
and do the checking in a bash shell :-)
[ -x /etc ] && my-prog /etc
source code:
# retrieve the uid of a file
# source code: my-prog.c
#
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
struct stat buffer;
int status;
char *fname;
fname=argv[1];
status = stat(fname, &buffer);
printf("%i",buffer.st_uid);
return 0;
}

Resources