How does the process of creating a file in ext2 file system look like?
I am trying to make a simple syscall which takes a path and creates given file - like touch.
For example, the code:
int main(void)
{
syscall(MY_SYSCALL_NUMBER, "/tmp/file");
}
Should create a file called "file" in /tmp.
Now how should the syscall itself work?
My work so far (I ommited error checking for readibility here):
asmlinkage long sys_ccp(const char __user *arg)
{
struct path path;
struct inode *new_inode;
struct qstring qname;
//ommited copy from user for simplicity
qname.name = arg;
qname.len = length(arg);
kern_path(src, LOOKUP_FOLLOW, &path);
new_inode = ext2_new_inode(path.dentry->d_parent->d_inode, S_IFREG, &qname);
}
This seems to work (I can see in logs that an inode is allocated), however, when I call ls on the directory I can't see the file there.
My idea was to add the new inode to struct dentry of directory, so I added this code:
struct dentry *new_dentry;
new_dentry = d_alloc(path.dentry->d_parent, &qname);
d_instantiate(new_dentry, new_inode);
However, this still doesn't seem to work (I can't see the file using ls).
How to implement this syscall correctly, what am I missing?
EDIT:
Regarding R.. answer - purpuse of this syscall is to play around with ext2 and learn about its design, so we can assumie that path is always valid, the filesystem is indeed ext2 and so on.
You're completely mixing up the abstraction layers involved. If something like your code could even work at all (not sure if it can), it would blow up badly and crash the kernel or lead to runaway wrong code execution if someone happened to make this syscall on a path that didn't actually correspond to an ext2 filesystem.
In the kernel's fs abstraction, the fact that the underlying filesystem is ext2 (or whatever it is) is irrelevant to the task of making a file on it. Rather all of this has to go through fs-type-agnostic layers which in turn end up using the fs-type-specific backends for the fs mounted at the path.
Related
I want to check the content of a file from Linux Kernel v3.0.8 knowing only struct inode *. I only need to read the beginning of a file pointed by this inode, then close and return. I don't care about additional information like filename/mountpoint etc.. In fact, the file may not have the name (like deleted but still open). Is it possible?
I finally did it like this:
This is needed.
struct path root;
struct file *filerd;
Get the init task fs root.
task_lock(&init_task);
get_fs_root(init_task.fs, &root);
task_unlock(&init_task);
Change dentry to this file:
root.dentry = d_find_alias(inode);
Open file:
filerd = file_open_root(root.dentry->d_parent, root.mnt,
root.dentry->d_name.name, O_RDONLY);
It worked for every process I tested and for different mount points, which surprised me.
I'm writing a program that iterates through a directory tree depth first (similar to the GNU find program) by recursively constructing paths to each file in the tree and stores the relative paths of encountered files. It also collects some statistics about these files. For this purpose I'm using the stat function.
I've notices that this fails for very deep directory hierarchies, i.e. long file paths, in accordance with stat's documentation.
Now my question is: what alternative approach could I use here that is guaranteed to work for paths of any length? (I don't need working code, just a rough outline would be sufficient).
As you are traversing, open each directory you traverse.
You can then get information about a file in that directory using fstatat. The fstatat function takes an additional parameter, dirfd. If you pass a handle to an open directory in that parameter, the path is interpreted as relative to that directory.
int fstatat(int dirfd, const char *pathname, struct stat *buf,
int flags);
The basic usage is:
int dirfd = open("directory path", O_RDONLY);
struct stat st;
int r = fstatat(dirfd, "relative file path", &st, 0);
You can, of course, also use openat instead of open, as you recurse. And the special value AT_FDCWD can be passed as dirfd to refer to the current working directory.
Caveats
It is easy to get into symlink loops and recurse forever. It is not uncommon to find symlink loops in practice. On my system, /usr/bin/X11 is a symlink to /usr/bin.
Alternatives
There are easier ways to traverse file hierarchies. Use ftw or fts instead, if you can.
First, a little background information to provide some motivation for this question: I've got a program that runs on a headless Linux server and reads/writes files on several removable external hard drives, each of which is formatted with ext4 filesystem. Very occasionally, the filesystem metadata on one of these drives gets corrupted for whatever reason (ext4 journalling notwithstanding), which can cause the ext4 filesystem drive to detect a problem and remount the partition as read-only, presumably as a precaution against cascading errors corrupting the drive further.
Okay, fair enough; but what I'd like to do now is add a function to my program that can detect when the drive is in this remounted-read-only state, so that it can pro-actively notify the user that his drive is in trouble.
My question is, what is an elegant/supported way to query a filesystem to find out if it is mounted read-only?
Attempting to write a file to the filesystem isn't good enough, because that could fail for other reasons, and also because I don't want to write to the filesystem if I don't have to.
My program could fopen("/proc/mounts", "r") and parse the lines of text that it generates (grepping for the "rw," token on the line corresponding to my partition), and I will if I have to, but that solution seems a bit hacky (too much like screen-scraping, liable to break if the text format ever changes).
So, is there some lightweight/purpose-built Linux system call that I could use that would tell me whether a given filesystem mount point (e.g. "/dev/sda1") is currently mounted read-only? It seems like stat() might be able to do it, but I can't see how.
The getmntent() family should meet your needs.
NAME
getmntent, setmntent, addmntent, endmntent, hasmntopt, getmntent_r -
get filesystem descriptor file entry
SYNOPSIS
#include <stdio.h>
#include <mntent.h>
FILE *setmntent(const char *filename, const char *type);
struct mntent *getmntent(FILE *stream);
int addmntent(FILE *stream, const struct mntent *mnt);
int endmntent(FILE *streamp);
char *hasmntopt(const struct mntent *mnt, const char *opt);
/* GNU extension */
#include <mntent.h>
struct mntent *getmntent_r(FILE *streamp, struct mntent *mntbuf,
char *buf, int buflen);
DESCRIPTION
These routines are used to access the filesystem description file
/etc/fstab and the mounted filesystem description file /etc/mtab.
The setmntent() function opens the filesystem description file
filename and returns a file pointer which can be used by getmntent().
The argument type is the type of access required and can take the same
values as the mode argument of fopen(3).
The getmntent() function reads the next line of the filesystem
description file from stream and returns a pointer to a structure
containing the broken out fields from a line in the file. The pointer
points to a static area of memory which is overwritten by subsequent
calls to getmntent().
The addmntent() function adds the mntent structure mnt to the end of
the open stream.
The endmntent() function closes the stream associated with the
filesystem description file.
The hasmntopt() function scans the mnt_opts field (see below) of the
mntent structure mnt for a substring that matches opt. See
and mount(8) for valid mount options.
The reentrant getmntent_r() function is similar to getmntent(), but
stores the struct mount in the provided *mntbuf and stores the strings
pointed to by the entries in that struct in the provided array buf of
size buflen.
The mntent structure is defined in as follows:
struct mntent {
char *mnt_fsname; /* name of mounted filesystem */
char *mnt_dir; /* filesystem path prefix */
char *mnt_type; /* mount type (see mntent.h) */
char *mnt_opts; /* mount options (see mntent.h) */
int mnt_freq; /* dump frequency in days */
int mnt_passno; /* pass number on parallel fsck */
};
...
The easiest way to check that the filesystem of an open file for writing has become mounted read-only is to check the errno variable for EROFS error.
If you don't have the possibility of having a writable directory or file in that filesystem, you cannot get a portable way of checking if the filesystem has become read only (more if it has become so due to device errors)
Another way is to ask the administrator to check, or try to read the /proc/mounts file yourself. But this is linux specific only.
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.
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;
}