1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <Efl.h>
6 
7 typedef struct _Efl_File_Data Efl_File_Data;
8 struct _Efl_File_Data
9 {
10    Eina_Stringshare *vpath; /* efl_file_set */
11    Eina_Stringshare *key; /* efl_file_key_set */
12    Eina_File *file; /* efl_file_mmap_set */
13    time_t mtime;
14    Eina_Bool file_opened : 1; /* if `file` was opened implicitly during load */
15    Eina_Bool setting : 1; /* set when this file is internally calling methods to avoid infinite recursion */
16    Eina_Bool loaded : 1; /* whether the currently set file properties have been loaded */
17 };
18 
19 EOLIAN static void
_efl_file_unload(Eo * obj,Efl_File_Data * pd)20 _efl_file_unload(Eo *obj, Efl_File_Data *pd)
21 {
22    if (!pd->loaded) return;
23    if (!pd->file) return;
24    if (!pd->file_opened) return;
25    pd->setting = 1;
26    eina_file_close(pd->file); // close matching open (dup in _efl_file_mmap_set) OK
27    pd->file = NULL;
28    efl_file_mmap_set(obj, NULL);
29    pd->setting = 0;
30    pd->loaded = pd->file_opened = EINA_FALSE;
31 }
32 
33 EOLIAN static Eina_Error
_efl_file_load(Eo * obj,Efl_File_Data * pd)34 _efl_file_load(Eo *obj, Efl_File_Data *pd)
35 {
36    Eina_Error ret = 0;
37 
38    if (pd->loaded) return 0;
39    EINA_SAFETY_ON_NULL_RETURN_VAL(pd->vpath, ENOENT);
40    errno = 0;
41    if (!pd->file)
42      {
43         Eina_File *f;
44         f = eina_file_open(pd->vpath, EINA_FALSE);
45         if (!f) return errno ?: ENOENT;
46         pd->file_opened = EINA_TRUE;
47         pd->setting = 1;
48         ret = efl_file_mmap_set(obj, f);
49         pd->setting = 0;
50         if (ret) pd->file_opened = EINA_FALSE;
51         eina_file_close(f); // close matching open OK
52      }
53    pd->loaded = !ret;
54    return ret;
55 }
56 
57 EOLIAN static Eina_Error
_efl_file_mmap_set(Eo * obj,Efl_File_Data * pd,const Eina_File * f)58 _efl_file_mmap_set(Eo *obj, Efl_File_Data *pd, const Eina_File *f)
59 {
60    Eina_Error err = 0;
61    Eina_File *file = NULL;
62 
63    if (f == pd->file) return 0;
64    if (f)
65      {
66         file = eina_file_dup(f);
67         if (!file) return errno;
68      }
69    if (pd->file) eina_file_close(pd->file); // close matching open (dup above) OK
70    pd->file = file;
71    pd->loaded = EINA_FALSE;
72 
73    if (!pd->setting)
74      {
75         /* avoid infinite recursion */
76         pd->setting = 1;
77         err = efl_file_set(obj, eina_file_filename_get(pd->file));
78         pd->setting = 0;
79      }
80    return err;
81 }
82 
83 EOLIAN static const Eina_File *
_efl_file_mmap_get(const Eo * obj EINA_UNUSED,Efl_File_Data * pd)84 _efl_file_mmap_get(const Eo *obj EINA_UNUSED, Efl_File_Data *pd)
85 {
86    return pd->file;
87 }
88 
89 EOLIAN static Eina_Error
_efl_file_file_set(Eo * obj,Efl_File_Data * pd,const char * file)90 _efl_file_file_set(Eo *obj, Efl_File_Data *pd, const char *file)
91 {
92    char *tmp;
93    Eina_Error err = 0;
94    Eina_Bool same;
95    struct stat st;
96 
97    tmp = (char*)(file);
98    if (tmp)
99      tmp = eina_vpath_resolve(tmp);
100 
101    same = !eina_stringshare_replace(&pd->vpath, tmp ?: file);
102    free(tmp);
103    if (file)
104      {
105         err = stat(pd->vpath, &st);
106         if (same && (!err)) same = st.st_mtime == pd->mtime;
107      }
108    if (same) return err;
109    pd->mtime = file && (!err) ? st.st_mtime : 0;
110    pd->loaded = EINA_FALSE;
111    if (pd->setting)
112      err = 0; /* this is from mmap_set, which may provide a virtual file */
113    else
114      {
115         pd->setting = 1;
116         err = efl_file_mmap_set(obj, NULL);
117         pd->setting = 0;
118      }
119    return err;
120 }
121 
122 EOLIAN static Eina_Stringshare *
_efl_file_file_get(const Eo * obj EINA_UNUSED,Efl_File_Data * pd)123 _efl_file_file_get(const Eo *obj EINA_UNUSED, Efl_File_Data *pd)
124 {
125    return pd->vpath;
126 }
127 
128 EOLIAN static void
_efl_file_key_set(Eo * obj EINA_UNUSED,Efl_File_Data * pd,const char * key)129 _efl_file_key_set(Eo *obj EINA_UNUSED, Efl_File_Data *pd, const char *key)
130 {
131    if (eina_stringshare_replace(&pd->key, key))
132      pd->loaded = 0;
133 }
134 
135 EOLIAN static Eina_Stringshare *
_efl_file_key_get(const Eo * obj EINA_UNUSED,Efl_File_Data * pd)136 _efl_file_key_get(const Eo *obj EINA_UNUSED, Efl_File_Data *pd)
137 {
138    return pd->key;
139 }
140 
141 EOLIAN static Eina_Bool
_efl_file_loaded_get(const Eo * obj EINA_UNUSED,Efl_File_Data * pd)142 _efl_file_loaded_get(const Eo *obj EINA_UNUSED, Efl_File_Data *pd)
143 {
144    return pd->loaded;
145 }
146 
147 EOLIAN static void
_efl_file_efl_object_destructor(Eo * obj,Efl_File_Data * pd)148 _efl_file_efl_object_destructor(Eo *obj, Efl_File_Data *pd)
149 {
150    eina_stringshare_del(pd->vpath);
151    eina_stringshare_del(pd->key);
152    eina_file_close(pd->file); // close matching open (dup in _efl_file_mmap_set) OK
153    pd->vpath = NULL;
154    pd->key = NULL;
155    pd->file = NULL;
156    efl_destructor(efl_super(obj, EFL_FILE_MIXIN));
157 }
158 
159 EOLIAN static Eo *
_efl_file_efl_object_finalize(Eo * obj,Efl_File_Data * pd)160 _efl_file_efl_object_finalize(Eo *obj, Efl_File_Data *pd)
161 {
162    obj = efl_finalize(efl_super(obj, EFL_FILE_MIXIN));
163    if (!obj) return NULL;
164    if (pd->file || pd->vpath) efl_file_load(obj);
165    return obj;
166 }
167 
168 ////////////////////////////////////////////////////////////////////////////
169 
170 EAPI Eina_Bool
efl_file_simple_load(Eo * obj,const char * file,const char * key)171 efl_file_simple_load(Eo *obj, const char *file, const char *key)
172 {
173    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
174    efl_ref(obj);
175    if (efl_file_set(obj, file))
176      {
177         EINA_LOG_ERR("File set to '%s' on '%s' failed.", file, efl_debug_name_get(obj));
178         goto fail;
179      }
180    efl_file_key_set(obj, key);
181    if (file)
182      {
183         if (efl_file_load(obj)) goto fail;
184         efl_unref(obj);
185         return EINA_TRUE;
186      }
187    efl_file_unload(obj);
188    efl_unref(obj);
189    return EINA_TRUE;
190 fail:
191    efl_unref(obj);
192    return EINA_FALSE;
193 }
194 
195 EAPI Eina_Bool
efl_file_simple_mmap_load(Eo * obj,const Eina_File * file,const char * key)196 efl_file_simple_mmap_load(Eo *obj, const Eina_File *file, const char *key)
197 {
198    EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
199    efl_ref(obj);
200    EINA_SAFETY_ON_TRUE_GOTO(efl_file_mmap_set(obj, file), fail);
201    efl_file_key_set(obj, key);
202    if (file)
203      {
204         if (efl_file_load(obj)) goto fail;
205         efl_unref(obj);
206         return EINA_TRUE;
207      }
208    efl_file_unload(obj);
209    efl_unref(obj);
210    return EINA_TRUE;
211 fail:
212    efl_unref(obj);
213    return EINA_FALSE;
214 }
215 
216 EAPI void
efl_file_simple_get(const Eo * obj,const char ** file,const char ** key)217 efl_file_simple_get(const Eo *obj, const char **file, const char **key)
218 {
219    efl_ref((Eo*)obj);
220    if (file) *file = efl_file_get(obj);
221    if (key) *key = efl_file_key_get(obj);
222    efl_unref((Eo*)obj);
223 }
224 
225 EAPI void
efl_file_simple_mmap_get(const Eo * obj,const Eina_File ** file,const char ** key)226 efl_file_simple_mmap_get(const Eo *obj, const Eina_File **file, const char **key)
227 {
228    efl_ref((Eo*)obj);
229    if (file) *file = efl_file_mmap_get(obj);
230    if (key) *key = efl_file_key_get(obj);
231    efl_unref((Eo*)obj);
232 }
233 
234 #include "interfaces/efl_file.eo.c"
235 #include "interfaces/efl_file_save.eo.c"
236