451ab91e |
1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * |
2 | * Mupen64plus-core - osal/files_win32.c * |
3 | * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * |
4 | * Copyright (C) 2009 Richard Goedeken * |
5 | * * |
6 | * This program is free software; you can redistribute it and/or modify * |
7 | * it under the terms of the GNU General Public License as published by * |
8 | * the Free Software Foundation; either version 2 of the License, or * |
9 | * (at your option) any later version. * |
10 | * * |
11 | * This program is distributed in the hope that it will be useful, * |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
14 | * GNU General Public License for more details. * |
15 | * * |
16 | * You should have received a copy of the GNU General Public License * |
17 | * along with this program; if not, write to the * |
18 | * Free Software Foundation, Inc., * |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * |
20 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ |
21 | |
22 | /* This file contains the definitions for the unix-specific file handling |
23 | * functions |
24 | */ |
25 | |
26 | #include <sys/types.h> |
27 | #include <sys/stat.h> |
28 | #include <stdlib.h> |
29 | #include <string.h> |
30 | #include <stdio.h> |
31 | #include <direct.h> |
32 | #include <shlobj.h> |
33 | |
34 | #include "files.h" |
35 | #include "api/m64p_types.h" |
36 | #include "api/callbacks.h" |
37 | |
38 | /* definitions for system directories to search when looking for shared data files */ |
39 | #if defined(SHAREDIR) |
40 | #define XSTR(S) STR(S) /* this wacky preprocessor thing is necessary to generate a quote-enclosed */ |
41 | #define STR(S) #S /* copy of the SHAREDIR macro, which is defined by the makefile via gcc -DSHAREDIR="..." */ |
42 | static const int datasearchdirs = 2; |
43 | static const char *datasearchpath[2] = { XSTR(SHAREDIR), ".\\" }; |
44 | #undef STR |
45 | #undef XSTR |
46 | #else |
47 | static const int datasearchdirs = 1; |
48 | static const char *datasearchpath[1] = { ".\\" }; |
49 | #endif |
50 | |
51 | /* local functions */ |
52 | static int search_dir_file(char *destpath, const char *path, const char *filename) |
53 | { |
54 | struct _stat fileinfo; |
55 | |
56 | /* sanity check to start */ |
57 | if (destpath == NULL || path == NULL || filename == NULL) |
58 | return 1; |
59 | |
60 | /* build the full filepath */ |
61 | strcpy(destpath, path); |
62 | if (destpath[strlen(destpath)-1] != '\\') |
63 | strcat(destpath, "\\"); |
64 | strcat(destpath, filename); |
65 | |
66 | /* test for a valid file */ |
67 | if (_stat(destpath, &fileinfo) != 0) |
68 | return 2; |
69 | if ((fileinfo.st_mode & _S_IFREG) == 0) |
70 | return 3; |
71 | |
72 | /* success - file exists and is a regular file */ |
73 | return 0; |
74 | } |
75 | |
76 | /* global functions */ |
77 | |
78 | int osal_mkdirp(const char *dirpath, int mode) |
79 | { |
80 | char *mypath, *currpath, *lastchar; |
81 | struct _stat fileinfo; |
82 | |
83 | // Create a copy of the path, so we can modify it |
84 | mypath = currpath = _strdup(dirpath); |
85 | if (mypath == NULL) |
86 | return 1; |
87 | |
88 | // if the directory path ends with a separator, remove it |
89 | lastchar = mypath + strlen(mypath) - 1; |
90 | if (strchr(OSAL_DIR_SEPARATORS, *lastchar) != NULL) |
91 | *lastchar = 0; |
92 | |
93 | // Terminate quickly if the path already exists |
94 | if (_stat(mypath, &fileinfo) == 0 && (fileinfo.st_mode & _S_IFDIR)) |
95 | goto goodexit; |
96 | |
97 | while ((currpath = strpbrk(currpath + 1, OSAL_DIR_SEPARATORS)) != NULL) |
98 | { |
99 | // if slash is right after colon, then we are looking at drive name prefix (C:\) and should |
100 | // just skip it, because _stat and _mkdir will both fail for "C:" |
101 | if (currpath > mypath && currpath[-1] == ':') |
102 | continue; |
103 | *currpath = '\0'; |
104 | if (_stat(mypath, &fileinfo) != 0) |
105 | { |
106 | if (_mkdir(mypath) != 0) |
107 | goto errorexit; |
108 | } |
109 | else if (!(fileinfo.st_mode & _S_IFDIR)) |
110 | { |
111 | goto errorexit; |
112 | } |
113 | *currpath = OSAL_DIR_SEPARATORS[0]; |
114 | } |
115 | |
116 | // Create full path |
117 | if (_mkdir(mypath) != 0) |
118 | goto errorexit; |
119 | |
120 | goodexit: |
121 | free(mypath); |
122 | return 0; |
123 | errorexit: |
124 | free(mypath); |
125 | return 1; |
126 | } |
127 | |
128 | const char * osal_get_shared_filepath(const char *filename, const char *firstsearch, const char *secondsearch) |
129 | { |
130 | static char retpath[_MAX_PATH]; |
131 | int i; |
132 | |
133 | /* if caller gave us any directories to search, then look there first */ |
134 | if (firstsearch != NULL && search_dir_file(retpath, firstsearch, filename) == 0) |
135 | return retpath; |
136 | if (secondsearch != NULL && search_dir_file(retpath, secondsearch, filename) == 0) |
137 | return retpath; |
138 | |
139 | /* otherwise check our standard paths */ |
140 | if (search_dir_file(retpath, osal_get_user_configpath(), filename) == 0) |
141 | return retpath; |
142 | for (i = 0; i < datasearchdirs; i++) |
143 | { |
144 | if (search_dir_file(retpath, datasearchpath[i], filename) == 0) |
145 | return retpath; |
146 | } |
147 | |
148 | /* we couldn't find the file */ |
149 | return NULL; |
150 | } |
151 | |
152 | const char * osal_get_user_configpath(void) |
153 | { |
154 | static char chHomePath[MAX_PATH]; |
155 | LPITEMIDLIST pidl; |
156 | LPMALLOC pMalloc; |
157 | struct _stat fileinfo; |
158 | |
159 | // Get item ID list for the path of user's personal directory |
160 | HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl); |
161 | // get the path in a char string |
162 | SHGetPathFromIDList(pidl, chHomePath); |
163 | // do a bunch of crap just to free some memory |
164 | hr = SHGetMalloc(&pMalloc); |
165 | pMalloc->lpVtbl->Free(pMalloc, pidl); |
166 | pMalloc->lpVtbl->Release(pMalloc); |
167 | |
168 | // tack on 'mupen64plus' |
169 | if (chHomePath[strlen(chHomePath)-1] != '\\') |
170 | strcat(chHomePath, "\\"); |
171 | strcat(chHomePath, "Mupen64Plus"); |
172 | |
173 | // if this directory doesn't exist, then make it |
174 | if (_stat(chHomePath, &fileinfo) == 0) |
175 | { |
176 | strcat(chHomePath, "\\"); |
177 | return chHomePath; |
178 | } |
179 | else |
180 | { |
181 | osal_mkdirp(chHomePath, 0); |
182 | if (_stat(chHomePath, &fileinfo) == 0) |
183 | { |
184 | strcat(chHomePath, "\\"); |
185 | return chHomePath; |
186 | } |
187 | } |
188 | |
189 | /* otherwise we are in trouble */ |
190 | DebugMessage(M64MSG_ERROR, "Failed to open configuration directory '%s'.", chHomePath); |
191 | return NULL; |
192 | } |
193 | |
194 | const char * osal_get_user_datapath(void) |
195 | { |
196 | // in windows, these are all the same |
197 | return osal_get_user_configpath(); |
198 | } |
199 | |
200 | const char * osal_get_user_cachepath(void) |
201 | { |
202 | // in windows, these are all the same |
203 | return osal_get_user_configpath(); |
204 | } |
205 | |
206 | |