summaryrefslogtreecommitdiffstats
path: root/iOS/fopen.m
blob: 8d2e79084538e74f86436e388e0098e16aa653d5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <stdio.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <Foundation/Foundation.h>
 
static FILE *(*libc_fopen)(const char *, const char *) = NULL;

__attribute__((constructor))
static void pre_main(void)
{
    /*
     * Pull reference to fopen(3) from libc.
     */
    void *handle = dlopen("libSystem.B.dylib",RTLD_LAZY);

    if (handle) {
        libc_fopen = dlsym(handle,"fopen");
        dlclose(handle);
    }

    /*
     * Change to Documents directory.
     */
    NSString *docs = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

    NSFileManager *filemgr = [NSFileManager defaultManager];
    [filemgr changeCurrentDirectoryPath: docs];
    [filemgr release];
}

char *mkdirhier(char *path)
{
    char *slash;
    struct stat buf;

    if (path[0]=='.' && path[1]=='/') path+=2;

    if ((slash = strrchr(path,'/'))) {
	*slash = '\0';
	if (stat(path,&buf)==0) {
	    *slash = '/';
	    return NULL;
	}
	(void)mkdirhier(path);
	mkdir (path,0777);
	*slash = '/';
    }

    return slash;
}
/*
 * Replacement fopen(3)
 */
FILE *fopen(const char *filename, const char *mode)
{
    FILE *ret;

    if ((ret = (*libc_fopen)(filename,mode)) == NULL) {
        /*
         * If file is not present in Documents directory, try from Bundle.
         */
        NSString *nsspath = [NSString stringWithFormat:@"%@/%s",
                                   [[NSBundle mainBundle] bundlePath],
                                   filename];

        if ((ret = (*libc_fopen)([nsspath cStringUsingEncoding:NSUTF8StringEncoding],mode)) == NULL &&
	    mode[0]=='w' &&
	    ((filename[0]!='.' && filename[0]!='/') ||
	     (filename[0]=='.' && filename[1]=='/')) ) {
	    /*
	     * If not present in Bundle, create directory in Documents
	     */
	    char *path = strdup(filename), *slash;
	    static int once = 1;

	    if ((slash = mkdirhier(path)) && once) {
		/*
		 * For some reason iOS truncates first created file
		 * upon program exit, so we create one preemptively...
		 */
		once = 0;
		strcpy(slash,"/.0");
		creat(path,0444);
	    }
	    free(path);
	    ret = (*libc_fopen)(filename,mode);
	}
    }

    return ret;
}