creat system call fail to set permissions - permissions

I need to use creat system call to create file (it is used in legacy code and I'm not allowed to change this; example below is simplified one but the problem is just the same). I have the following code:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
umask(0);
int hndl = creat("abc.dat", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); // == 0660
close(hndl);
}
File is created as expected (I checked the timestamp also), but the permissions are different from 0660:
$ gcc creat.c && ./a.out && ll | grep abc
-rwx---r-x 1 ulysses ulysses 0 May 7 19:42 abc.dat*
which are 0705. I tried to use 0660 literally and had the same result. Am I missing something?

Your code looks correct and should do what you want. You should check whether your program actually did create the file: if it did exist already, creat() would succeed without error and update the timestamp, but not change the permissions.

Related

assertion from valgrind mc_main.c

My valgrind runs reports errors like this
Memcheck: mc_main.c:8292 (mc_pre_clo_init): Assertion 'MAX_PRIMARY_ADDRESS == 0x1FFFFFFFFFULL' failed.
What does this mean? Is it a valgrind internal error or an error from my program?
This is a valgrind internal error. This is very weird, as this failed
assertion is a self check done very early on.
You should file a bug on valgrind bugzilla, reporting all the needed
details (version, platform, ...)
From the Valgrind source code (from git HEAD)
/* Only change this. N_PRIMARY_MAP *must* be a power of 2. */
#if VG_WORDSIZE == 4
/* cover the entire address space */
# define N_PRIMARY_BITS 16
#else
/* Just handle the first 128G fast and the rest via auxiliary
primaries. If you change this, Memcheck will assert at startup.
See the definition of UNALIGNED_OR_HIGH for extensive comments. */
# define N_PRIMARY_BITS 21
#endif
/* Do not change this. */
#define N_PRIMARY_MAP ( ((UWord)1) << N_PRIMARY_BITS)
/* Do not change this. */
#define MAX_PRIMARY_ADDRESS (Addr)((((Addr)65536) * N_PRIMARY_MAP)-1)
...
tl_assert(MAX_PRIMARY_ADDRESS == 0x1FFFFFFFFFULL);
So it looks like something has been changed that shouldn't have been.

error using yaml-cpp to get integer nested in key hierarchy

Initial Question
I have a config.yaml that has structure similar to
some_other_key: 34
a:
b:
c:
d: 3
I thought I could do
YAML::Node config = YAML::LoadFile(config_filename.c_str());
int x = config["a"]["b"]["c"]["d"].as<int>();
but I get
terminate called after throwing an instance of
'YAML::TypedBadConversion<int>'
what(): bad conversion
How do I descend through my config.yaml to extract a value like this? I also get that same exception if I mistype one of the keys in the path, so I can't tell from the error if I am accidentally working with a null node or if there is a problem converting a valid node's value to int
Follow up After First Replies
Thank you for replying! Maybe it is an issue with what is in the config.yaml? Here is a small example to reproduce,
yaml file: config2.yaml
daq_writer:
num: 3
num_per_host: 3
hosts:
- local
datasets:
small:
chunksize: 600
Python can read it:
Incidentally, I am on linux on rhel7, but from a python 3.6 environment, everything looks good:
$ python -c "import yaml; print(yaml.load(open('config2.yaml','r')))"
{'daq_writer': {'num_per_host': 3, 'num': 3, 'datasets': {'small': {'chunksize': 600}}, 'hosts': ['local']}}
C++ yaml-cpp code
The file yamlex.cpp:
#include <string>
#include <iostream>
#include "yaml-cpp/yaml.h"
int main() {
YAML::Node config = YAML::LoadFile("config2.yaml");
int small_chunksize = config["daq_writer"]["datasets"]["smal"]["chunksize"].as<int>();
}
When I compile and run this, I get:
(lc2) psanagpu101: ~/rel/lc2-hdf5-110 $ c++ --std=c++11 -Iinclude -Llib -lyaml-cpp yamlex.cpp
(lc2) psanagpu101: ~/rel/lc2-hdf5-110 $ LD_LIBRARY_PATH=lib ./a.out
terminate called after throwing an instance of 'YAML::TypedBadConversion<int>'
what(): bad conversion
Aborted (core dumped)
(lc2) psanagpu101: ~/rel/lc2-hdf5-110 $ gcc --version
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
I have been able to read top level keys, like the some_other_key that I referenced above, but I got an error when I went after this nested key. Good to know that syntax works!
You have a typo in your keys: instead of "small", you wrote "smal".

Preprocessor macro C/Objective-C

Hello I am trying to Make A Macro that gets a parameter and tries to add postFix to it.
#define myPostFix HelloWorld
#define macro(x) x ##myPostFix
#define CAlgThreadHandleObject macro(CAlgThreadHandleObject)
Expected behavior is to get
CAlgThreadHandleObjectHelloWorld
What I actually get is:
CAlgThreadHandleObjectmyPostFix
Can Some1 help me to get the expected behavior please?
Please note that myPostFix is something I have to define in project GCC definitions and it should vary from project to project.
Try:
#define myPostFix HelloWorld
#define macro_2(x, y) x##y
#define macro_1(x, y) macro_2(x, y)
#define macro(x) macro_1(x, myPostFix)
#define CAlgThreadHandleObject macro(CAlgThreadHandleObject)
You need the intermediate macro_1 to let the preprocessor substitute myPostFix assignement, then macro_2 to concatenate strings.
This solution let you assign myPostFix to the value you want.
To clarify how preprocessor and symbol replacement works consider that the preprocessing translation phase is not recursive on parameters, so the translation need to pass through a forced parameter expansion more than one time up to expand all parameters.
In our case:
CAlgThreadHandleObject expands to : macro(CAlgThreadHandleObject)
macro(CAlgThreadHandleObject) expands to : macro_1(CAlgThreadHandleObject, myPostFix)
macro_1 expands to: macro_2(CAlgThreadHandleObject, HelloWorld)
And last macro_2 expands to: CAlgThreadHandleObjectHelloWorld
You actually need to go three layers deep with this one in order to get the macro to expand properly. I can't pretend to understand the exact reasoning why this is necessary (not that I want to understand...)
#define MY_ADDPOSTFIX3(x, y) x ## y
#define MY_ADDPOSTFIX2(x, y) MY_ADDPOSTFIX3(x, y)
#define MY_ADDPOSTFIX(x) MY_ADDPOSTFIX2(x, MY_POSTFIX)
MY_ADDPOSTFIX(Func)
You can test this:
$ gcc -E test.c -DMY_POSTFIX=HelloWorld
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
FuncHelloWorld
And...
$ gcc -E test.c -DMY_POSTFIX=Goodbye | tail -n 1
FuncGoodbye
Simply pass it through another call of the macro macro so the define is expanded. I slightly changed the macros, but the functionality is the same:
#define myPostFix HelloWorld
#define macro2(x,y) x##y
#define macro(x,y) macro2(x,y)
#define CAlgThreadHandleObject macro(CAlgThreadHandleObject,myPostFix)

How to get full path (including mount directory) for file path?

I'm working on a plugin for Coda, and I'm running into a strange problem when trying to compare file paths to a sqlite row.
Basically, NSOpenPanel returns an NSURL which returns a path like this:
/Users/michael/Documents/xcode stuff/hM github/Plugin/filename
And Coda returns the current file path as this:
/Volumes/Macintosh HD/Users/michael/Documents/xcode stuff/hM github/Plugin/filename
I need to be able to retrieve a sqlite row tied to this file (which was initially created when the user selects a file through NSOpenPanel) given the path from Coda.
Is there a way to get a file's actual full path, including Volume information?
Alternatively, is there a better way to store a reference to a file that could be easily retrievable, regardless of the given path?
update
I've realized that Coda modifies saved files in such a way that you cannot rely on a file's inode number to remain consistent, so trojanfoe's answer will not work for me.
Looking at the following:
miranda-6:~ jeremyp$ ls -l /Volumes
total 8
drwxr-xr-x 1 jeremyp staff 8192 23 Oct 06:54 BOOTCAMP
drwxrwxr-x# 20 jeremyp staff 748 23 Oct 11:22 G-DRIVE
lrwxr-xr-x 1 root admin 1 28 Oct 07:25 Macintosh HD -> /
drwxrwxrwx 0 root wheel 0 1 Nov 16:28 MobileBackups
miranda-6:~ jeremyp$
/Volumes/Macintosh HD is a symbolic link to /.
So what you should do (IMO), is iterate through the items in /Volumes until you find the one that is a symbolic link to / Then whenever you get a file path from Coda that starts with /Volumes/<the item linked to / >, you strip that off before doing a search for it in your database.
You can use NSFileManager attributesOfItemAtPath:error: to find out if you have a symlink and NSFileManager -destinationOfSymbolicLinkAtPath:error: to find out where the symlink goes.
A better way to uniquely identify a file, regardless of how it's specified (absolute, relative, or including the mount) is to use the file's device and inode number which are unique across the system:
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
static void get_file_details(const char *filename) {
struct stat statbuf;
if (stat(filename, &statbuf) == 0) {
printf("%s = %016llx%016llx\n", filename, (uint64_t)statbuf.st_dev, (uint64_t)statbuf.st_ino);
} else {
fprintf(stderr, "Failed to stat '%s': %s\n", filename, strerror(errno));
}
}
int main(int argc, const char **argv) {
for (int i = 1; i < argc; i++)
get_file_details(argv[i]);
return 0;
}
$ clang -o stattest stattest.c
$ ./stattest stat*
stattest = 00000000010000010000000001b1d48a
stattest.c = 00000000010000010000000001b1d43b
You'll need to decide how you format the device/inode combo, but the above format should work fine for most cases.

Using open() such that the file permission is guaranteed to be the same as that of files written out using the NSData file write methods

I'm currently using open() in the following way to write out a file:
NSString *path = #"/Users/enchilada/Desktop/file.txt";
int fd = open([path fileSystemRepresentation],
O_EXCL | O_CREAT | O_WRONLY,
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
My issue is the 3rd parameter. Is it “correct” in the sense that it’s guaranteed to yield the exact same permission under all circumstances as NSData’s regular writeToFile: methods?
I want to obtain the appropriate “default” permissions when using a plain open() instead of using Cocoa’s methods to write out files.
I have found the above permissions (rw-rw-rw-) to work, because the umask actually brings them down to (rw-r--r--). But my question is: Is this always guaranteed? What should my 3rd parameter actually be?
We can find out using dtruss. Here's my test program:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
#autoreleasepool {
[[NSData dataWithBytes:"hello\n" length:6] writeToFile:#"/tmp/data.out" atomically:NO];
}
return 0;
}
Here's my run log:
$ sudo dtruss ~/Library/Dev*/Xcode/De*/datatest-*/B*/P*/D*/datatest 2>&1 | fgrep data.out
open("/tmp/data.out\0", 0x601, 0x1B6) = 3 0
Hex 0x1B6 is octal 0666.
Yes 0666 is correct (at least for iOS 5), but the 2nd argument would be O_CREAT | O_TRUNC | O_WRONLY if you're not writing atomically (and O_CREAT | O_EXCL | O_RDWR on the temporary file if written atomically.)
Actually you could run your program in a debugger, set a break point at open, and then check the 3rd argument (p/o $r2 in gdb for ARM) to ensure.