Miriam Ruiz
random thoughts on technology and life











{September 17, 2007}   Storing data in $HOME directory

When packaging games, one of the operations I often have to do to the source code is modifying it so that it uses absolute file and directory names instead of relative ones. When coders develop for Windows, or when they develop their games to be able to play them from their home directory, they just would go that way and won’t care about it, but when the idea is installing the files in the system, the Filesystem Hierarchy Standard (FHS) must be respected, and thus things will need to be place in their proper directories.

For read-only files, this is not a big deal, all that has to be done is replacing the relative file name in the file opening commands with the absolute one, doing fopen(“/usr/share/games/package/dir/file”) instead of fopen(“dir/file”). I usually prefer to do it like fopen(DATADIR “/dir/file”) and set DATADIR from the Makefile, with a -DDATADIR=\”/usr/share/games/package\” switch added to the CFLAGS, and maybe also setting it inside the code if it’s not previously defined (#ifndef and so).

There are some files and directories in which doing this is not possible, because they want read-write permissions. This files include saving the configuration, hiscores, new levels created with the game editor, game saves and so. They might be moved to some directory under “/var/lib/”, and create a new group en the system so that it’s writable, and so on. I don’t like that approach a single bit. I prefer to move all tthat data to the user’s directory. This is not as straightforward as it was for read-only data, but it’s not really that difficult anyway. It would be more or less like:

#ifndef _WIN32
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <pwd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif

#ifndef _WIN32
char file[PATH_MAX];
char *home;
struct passwd *passwd;
if (!getuid() || !(home = getenv("HOME"))){
passwd = getpwuid (getuid());
home=passwd->pw_dir;
if (!home){
fprintf(stderr, "$HOME is not defined.\n");
exit(-1)
}
}
if (strlen(home) > PATH_MAX - sizeof("/.package/settings.ini")){
fprintf(stderr, "$HOME is excessively long.\n");
exit(-1)
}
snprintf(file, sizeof(file), "%s/.package", home);
mkdir(file, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
strncat(file, "/settings.ini", sizeof(file)-1);
#else
char file[21];
snprintf(file, sizeof(file), "./Data/settings.ini");
#endif
FILE *f = fopen(file, "w");

Sometimes you also need that the files are already created, you can check if they already exist with stat(), and then acting accordingly, either creating them from your C code, or maybe triggering a system() shell call whith whatever is needed.

struct stat stat_buf;
stat(file, &stat_buf);
if (stat(file, &stat_buf) == -1){
int settings_fd = creat(file, O_WRONLY);
close(settings_fd);
}

NOTE: I’ve updated the code to add some suggestions. Thanks to Gonéri Le Bouder and Nico Golde.




about

This is a personal webpage that belongs to Miriam Ruiz.
If you want to contact her, you can do at:
webmistress(at)miriamruiz(dot)es.

pages
categories
archive
twitter
calendar
September 2007
M T W T F S S
« Aug   Oct »
 12
3456789
10111213141516
17181920212223
24252627282930
credits
WikiLeaks

La Lista de Sinde