I call the following code in C:
fileCreatefd = mkstemp(fileName);
I see that the file is created with permissions 600 (-rw-------). I want to create this temp file as -rw-rw-rw-
I tried playing around with umask but that only applies a mask over the file permissions -- at least thats my understanding. So how can i create a file with permissions 666?
Thanks
You cannot create it 0666 with mkstemp. You can change the permissions afterwards, if that is sufficient for your application, with fchmod.
fileCreatefd = mkstemp(fileName);
fchmod(fileCreatefd, 0666)
The mkstemp() function generates a unique temporary filename from template, creates and opens the file, and returns an open file descriptor for the file.
The last six characters of template must be "XXXXXX" and these are replaced with a string that makes the filename unique. Since it will be modified, template must not be a string constant, but should be declared as a character array.
The file is created with permissions 0600, that is, read plus write for owner only. (In glibc versions 2.06 and earlier, the file is created with permissions 0666, that is, read and writefor all users.) The returned file descriptor provides both read and write access to the file. The file is opened with the open(2) O_EXCL flag, guaranteeing that the caller is the process that creates the file.
More generally, the POSIX specification of mkstemp() does not say anything about file modes, so the application should make sure its file mode creation mask (umask(2)) is set appropriately before calling mkstemp() (and mkostemp()).
So after creating the File Use fchmod to change the file permission.
Related
In TCL there are four permission arguments of file. I want to open a new file and give permissions. Look following example:
open file_name.txt w 0666
We have permissions for the file owner/group/other in Linux. Why do we use 4 arguments in TCL? What is the fourth one (I am not sure it is the first one or last)?
The permissions argument is an integer representing 3 groups of 3 bits for owner/group/other. So rw permissions for all 3 groups would be 110110110 in binary. In decimal, that's 438. But that's not very obvious. This is why the argument is usually specified in octal. The old way to indicate that a number should be interpreted as octal is by adding a leading 0. But to be future proof, you better use 0o666 nowadays.
The documentation for open does say that acceptable argument patterns are:
open fileName
open fileName access
open fileName access permissions
And goes on to define permissions as:
If a new file is created as part of opening it, permissions (an integer) is used to set the permissions for the new file in conjunction with the process's file mode creation mask. Permissions defaults to 0666.
The arguments mostly map fairly closely to the arguments to the Unix open() system call and fopen() library call. It's pretty rare that you actually specify the permissions (and that's modified by your umask; Tcl doesn't expose any way of working with that) as the defaults usually work well for most applications.
If you need to alter the permissions of a file you've made, try file attributes:
# I prefer the symbolic permissions descriptors supported by this command
file attributes $fileName -permissions rw-rw-rw-
I'm new to Linux, still struggling to understand how permisson control work in Linux. The open function prototype is sth like :
int open(char *filename, int flags, mode_t mode);
Let's I have the following code:
fd = open("foo.txt", O_CREAT|O_RDWR, S_IRUSR)
and let's say the file "foo.txt" didn't exist before, so the above statment will create a file called "foo.txt", and current process who executes this open statment can read and write this file. But after this process terminates, If another process starts and tries to open this file. Below is my question:
Q1-Since the file was created with S_IRUSR(owner can read this file) in the first open call, does it mean that even I as owner of the file, if I start a new process to open this file again, I can only read this file and I cannot write this file, is my understanding correct?
If my understanding is correct, is it sensible/practicable that owners create sth that they cannot have full access to it later?
Q2-If my above understanding is correct, then in the second call to open by a new process. I can only call like:
fd = open("foo.txt", O_RDONLY) // uses flags like O_WRONLY or O_RDWR will throw an error?
since the first open specified the mode as S_IRUSR, which maps to O_RDONLY in the subsequent calls, is my understanding correct?
Correct, if you create the file with permissions S_IRUSR (often written in octal as 0400), then you will not be able to open the file for writing. Attempting to do so will fail and set errno to EACCES.
This is quite practical as it gives you a way to protect files you do not want to accidentally overwrite, as long as the permissions stay as they are. However, as the owner, you have the power to change the permissions later, using the chmod() system call. So it's not as though you have permanently lost the ability to write that file; you can give yourself back that ability whenever you want.
I have a hardlink the must always exist on the filesystem. What inode the hardlink points is not constant. I want to update the hardlink without adding a temporary entry to the directory.
(Creating a file without a directory entry can be done using open(2) with the temp flag.)
The issue I'm facing is with replacing/updating the hardlink. From the documentation on the relevant system calls, It seems that I have only two options, and neither avoids a temporary file:
Using renameat, it is possible to insure that the hardlink always exists. However, it must consume a hardlink and hence necessitating a temporary files (not to mention its inability to dereference symbolic links).
using linkat, it is possible to produce a hardlink without sacrificing another file. but it cannot overwrite existing files; requiring the deletion of the original hard link.
Is it at all possible to create a link to an inode that replaces an older link with the same name?
You need to have another file to which to switch the link. However
rename, renameat do not need the inode be linked in the same directory; they just require the inode to exist on the same filesystem, or more specifically on the same mount point; otherwise Linux rename fails with EXDEV:
EXDEV
oldpath and newpath are not on the same mounted filesystem. (Linux permits a filesystem to be mounted at multiple points, but rename() does not work across different
mount points, even if the same filesystem is mounted on both.)
Since Linux 3.11 there is a way to make a new file without linking it to the filesystem: open(2) has a new flag O_TMPFILE:
O_TMPFILE (since Linux 3.11)
Create an unnamed temporary file. The pathname argument
specifies a directory; an unnamed inode will be created in
that directory's filesystem. Anything written to the
resulting file will be lost when the last file descriptor is
closed, unless the file is given a name.
O_TMPFILE must be specified with one of O_RDWR or O_WRONLY
and, optionally, O_EXCL. If O_EXCL is not specified, then
linkat(2) can be used to link the temporary file into the
filesystem, making it permanent, using code like the
following:
char path[PATH_MAX];
fd = open("/path/to/dir", O_TMPFILE | O_RDWR,
S_IRUSR | S_IWUSR);
/* File I/O on 'fd'... */
snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd);
linkat(AT_FDCWD, path, AT_FDCWD, "/path/for/file",
AT_SYMLINK_FOLLOW);
In this case, the open() mode argument determines the file
permission mode, as with O_CREAT.
The manual tells that one of the 2 common use cases for O_TMPFILE is
Creating a file that is initially invisible, which is then
populated with data and adjusted to have appropriate
filesystem attributes (chown(2), chmod(2), fsetxattr(2),
etc.) before being atomically linked into the filesystem
in a fully formed state (using linkat(2) as described
above).
There are many downsides for this, apart from it being quite new: the file system must also support O_TMPFILE; ext[234] do support it, and so does XFS in 3.15; btrfs in 3.16; furthermore it might still not be a match for your case, as the linkat requires the AT_SYMLINK_FOLLOW which is not available for renameat; if the target name already exists, `linkat does not replace the the target.
I am writing a program to mimic the cp utility. However, I cannot get the file permissions to work correctly. I know that they are stored in the structure stat and stored in the st_mode field with stat.
My issue is that I do not get the write permission for the group or other categories, i.e. I get -rwxr-xr-x as the permissions for the file even though the source file is -rwxrwxrwx. The statement where I set the permissions is below.
if ( (dest_fd = open(dest_file, O_WRONLY|O_CREAT, (stats.st_mode & S_IRUSR)|(stats.st_mode & S_IWUSR)|(stats.st_mode & S_IXUSR)|(stats.st_mode & S_IRGRP)|(stats.st_mode & S_IWGRP)|(stats.st_mode & S_IXGRP)|(stats.st_mode & S_IROTH)|(stats.st_mode & S_IWOTH)| (stats.st_mode & S_IXOTH))) < 0)
{
printf("There was a problem opening the destination file.");
exit(EXIT_FAILURE);
}//ends the if statement opening the destination file.
The answers so far are right that the problem is umask, but rather than clearing the umask (this is dangerous if your program is multi-threaded or if you might be calling any library functions that create files) I would treat the umask as a user configuration variable you are not allowed to modify, and instead call fchmod on the files after creating them to give them the final permissions you want. This may be necessary anyway to give certain permissions like suid/sgid, which some kernels remove whenever the file is modified. I would also initially create the file with mode 0600, so that there's no race condition between opening it and changing permissions during which another user could get an open handle on the file.
The cause of the problem is
The permissions of the created file are (mode & ~umask)
Typically, umask is 022, so that prohibits creating world-writable files.
*nix masks out mode bits in files you create, but you can change the mask using the umask() function. man umask (perhaps man 2 umask) for details.
You can use the chmod(2) syscall to change the permissions of an existing file or directory or fchmod(2) to set the permissions given an open file descriptor.
To be more secure and to prevent exploitation of possible race conditions, you can use a very restrictive set of permissions while creating the file and then use chmod(2) to restore the original permissions. This is what cp -a does (except that it creates the file with the default permissions):
$ strace cp -a file file1
...
open("file1", O_WRONLY|O_TRUNC) = 4
...
fchmod(4, 0100640) = 0
...
chmod(2) and fchmod(2) are not affected by the value of the umask.
I have a process using C on Linux OS that writes data to a file. It uses open()/write() functions and I've been wondering if another process rm'd or mv'd the file. How can my process find out and recreate the file?
You can use fstat() to get the information about the open file. If the st_nlink field is zero, the file has been removed from the file system (possibly by being moved to a different file system, but there's no real way for you to determine that). There's a decent chance you have the only remaining reference to that file - though there might be other processes also holding it open. The disk space won't be released until the last process with an open file descriptor for the file finally closes the file.
If the st_nlink field is still positive, then your file still has a name somewhere out in the file system. You then need to use stat() to determine whether the st_dev and st_ino fields for the given file name match the same fields from the file descriptor. If the name still exists and has the same device and inode number, then it is 'the same' file (though the contents may have changed). If there's a difference, then the open file is different from the file specified by name.
Note that if you want to be sure that the given name is not a symbolic link to a moved copy of the file, then you would have to use lstat() on the file when you open it (to ensure it isn't a symlink at that point), and again when you check the file (instead of using stat()).
You can use the stat call to do this.
struct stat st;
if(stat("/tmp",&st) == 0)
printf(" /tmp is present\n");
else
/* Write code to create the file */