1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Library of functions to make emulated filesystem as independent as
5 * possible of the host filesystem's capabilities.
6 * This is the Unix version.
7 *
8 * Copyright 1999 Bernd Schmidt
9 */
10
11 #include "sysconfig.h"
12 #include "sysdeps.h"
13
14 #include "fsdb.h"
15 #include "misc.h"
16
17 /* these are deadly (but I think allowed on the Amiga): */
18 #define NUM_EVILCHARS 7
19 static TCHAR evilchars[NUM_EVILCHARS] = { '\\', '*', '?', '\"', '<', '>', '|' };
20
21 #define UAEFSDB_BEGINS "__uae___"
22 #define UAEFSDB_BEGINSX "__uae___*"
23 #define UAEFSDB_LEN 604
24 #define UAEFSDB2_LEN 1632
25
26 /* The on-disk format is as follows:
27 * Offset 0, 1 byte, valid
28 * Offset 1, 4 bytes, mode
29 * Offset 5, 257 bytes, aname
30 * Offset 262, 257 bytes, nname
31 * Offset 519, 81 bytes, comment
32 * Offset 600, 4 bytes, Windows-side mode
33 *
34 * 1.6.0+ Unicode data
35 *
36 * Offset 604, 257 * 2 bytes, aname
37 * Offset 1118, 257 * 2 bytes, nname
38 * 1632
39 */
40
41 #define TRACING_ENABLED 0
42 #if TRACING_ENABLED
43 #define TRACE(x) do { write_log x; } while(0)
44 #else
45 #define TRACE(x)
46 #endif
47
dos_errno(void)48 int dos_errno (void)
49 {
50 int e = errno;
51
52 switch (e) {
53 case ENOMEM: return ERROR_NO_FREE_STORE;
54 case EEXIST: return ERROR_OBJECT_EXISTS;
55 case EACCES: return ERROR_WRITE_PROTECTED;
56 case ENOENT: return ERROR_OBJECT_NOT_AROUND;
57 case ENOTDIR: return ERROR_OBJECT_WRONG_TYPE;
58 case ENOSPC: return ERROR_DISK_IS_FULL;
59 case EBUSY: return ERROR_OBJECT_IN_USE;
60 case EISDIR: return ERROR_OBJECT_WRONG_TYPE;
61 #if defined(ETXTBSY)
62 case ETXTBSY: return ERROR_OBJECT_IN_USE;
63 #endif
64 #if defined(EROFS)
65 case EROFS: return ERROR_DISK_WRITE_PROTECTED;
66 #endif
67 #if defined(ENOTEMPTY)
68 #if ENOTEMPTY != EEXIST
69 case ENOTEMPTY: return ERROR_DIRECTORY_NOT_EMPTY;
70 #endif
71 #endif
72 default:
73 TRACE (("FSDB: Unimplemented error: %s\n", strerror (e)));
74 return ERROR_NOT_IMPLEMENTED;
75 }
76 }
77
fsdb_name_invalid_2(const TCHAR * n,int dir)78 static int fsdb_name_invalid_2 (const TCHAR *n, int dir)
79 {
80 int i;
81 static char s1[MAX_DPATH];
82 static TCHAR s2[MAX_DPATH];
83 TCHAR a = n[0];
84 TCHAR b = (a == '\0' ? a : n[1]);
85 TCHAR c = (b == '\0' ? b : n[2]);
86 int l = _tcslen (n);
87
88 /* the reserved fsdb filename */
89 if (_tcscmp (n, FSDB_FILE) == 0)
90 return -1;
91
92 if (dir) {
93 if (n[0] == '.' && l == 1)
94 return -1;
95 if (n[0] == '.' && n[1] == '.' && l == 2)
96 return -1;
97 }
98
99 if (a >= 'a' && a <= 'z')
100 a -= 32;
101 if (b >= 'a' && b <= 'z')
102 b -= 32;
103 if (c >= 'a' && c <= 'z')
104 c -= 32;
105
106 /* these characters are *never* allowed */
107 for (i = 0; i < NUM_EVILCHARS; i++) {
108 if (_tcschr (n, evilchars[i]) != 0)
109 return 1;
110 }
111
112 s1[0] = 0;
113 s2[0] = 0;
114 //FIXME: ua_fs_copy (s1, MAX_DPATH, n, -1);
115 strcpy (s1, n);
116 au_fs_copy (s2, MAX_DPATH, s1);
117 if (_tcscmp (s2, n) != 0)
118 return 1;
119
120 return 0; /* the filename passed all checks, now it should be ok */
121 }
122
fsdb_name_invalid(const TCHAR * n)123 int fsdb_name_invalid (const TCHAR *n)
124 {
125 int v = fsdb_name_invalid_2 (n, 0);
126 if (v <= 0)
127 return v;
128 write_log (_T("FILESYS: '%s' illegal filename\n"), n);
129 return v;
130 }
131
fsdb_name_invalid_dir(const TCHAR * n)132 int fsdb_name_invalid_dir (const TCHAR *n)
133 {
134 int v = fsdb_name_invalid_2 (n, 1);
135 if (v <= 0)
136 return v;
137 write_log (_T("FILESYS: '%s' illegal filename\n"), n);
138 return v;
139 }
140
fsdb_exists(const char * nname)141 int fsdb_exists (const char *nname)
142 {
143 struct stat statbuf;
144 return (stat (nname, &statbuf) != -1);
145 }
146
147 /* For an a_inode we have newly created based on a filename we found on the
148 * native fs, fill in information about this file/directory. */
fsdb_fill_file_attrs(a_inode * base,a_inode * aino)149 int fsdb_fill_file_attrs (a_inode *base, a_inode *aino)
150 {
151 struct stat statbuf;
152 /* This really shouldn't happen... */
153 if (stat (aino->nname, &statbuf) == -1)
154 return 0;
155 aino->dir = S_ISDIR (statbuf.st_mode) ? 1 : 0;
156 aino->amigaos_mode = ((S_IXUSR & statbuf.st_mode ? 0 : A_FIBF_EXECUTE)
157 | (S_IWUSR & statbuf.st_mode ? 0 : A_FIBF_WRITE)
158 | (S_IRUSR & statbuf.st_mode ? 0 : A_FIBF_READ));
159 #ifdef ANDROID
160 // Always give execute & read permission
161 aino->amigaos_mode &= ~A_FIBF_EXECUTE;
162 aino->amigaos_mode &= ~A_FIBF_READ;
163 #endif
164 return 1;
165 }
166
fsdb_set_file_attrs(a_inode * aino)167 int fsdb_set_file_attrs (a_inode *aino)
168 {
169 struct stat statbuf;
170 int tmpmask = aino->amigaos_mode;
171 int mode;
172
173 if (stat (aino->nname, &statbuf) == -1)
174 return ERROR_OBJECT_NOT_AROUND;
175
176 mode = statbuf.st_mode;
177 /* Unix dirs behave differently than AmigaOS ones. */
178 if (! aino->dir) {
179 if (tmpmask & A_FIBF_READ)
180 mode &= ~S_IRUSR;
181 else
182 mode |= S_IRUSR;
183
184 if (tmpmask & A_FIBF_WRITE)
185 mode &= ~S_IWUSR;
186 else
187 mode |= S_IWUSR;
188
189 if (tmpmask & A_FIBF_EXECUTE)
190 mode &= ~S_IXUSR;
191 else
192 mode |= S_IXUSR;
193
194 chmod (aino->nname, mode);
195 }
196
197 aino->dirty = 1;
198 return 0;
199 }
200
201 /* return supported combination */
fsdb_mode_supported(const a_inode * aino)202 int fsdb_mode_supported (const a_inode *aino)
203 {
204 int mask = aino->amigaos_mode;
205 if (0 && aino->dir)
206 return 0;
207 if (fsdb_mode_representable_p (aino, mask))
208 return mask;
209 mask &= ~(A_FIBF_SCRIPT | A_FIBF_READ | A_FIBF_EXECUTE);
210 if (fsdb_mode_representable_p (aino, mask))
211 return mask;
212 mask &= ~A_FIBF_WRITE;
213 if (fsdb_mode_representable_p (aino, mask))
214 return mask;
215 mask &= ~A_FIBF_DELETE;
216 if (fsdb_mode_representable_p (aino, mask))
217 return mask;
218 return 0;
219 }
220
221 /* Return nonzero if we can represent the amigaos_mode of AINO within the
222 * native FS. Return zero if that is not possible. */
fsdb_mode_representable_p(const a_inode * aino,int amigaos_mode)223 int fsdb_mode_representable_p (const a_inode *aino, int amigaos_mode)
224 {
225 int mask = amigaos_mode ^ 15;
226
227 if (0 && aino->dir)
228 return amigaos_mode == 0;
229
230 if (mask & A_FIBF_SCRIPT) /* script */
231 return 0;
232 if ((mask & 15) == 15) /* xxxxRWED == OK */
233 return 1;
234 if (!(mask & A_FIBF_EXECUTE)) /* not executable */
235 return 0;
236 if (!(mask & A_FIBF_READ)) /* not readable */
237 return 0;
238 if ((mask & 15) == (A_FIBF_READ | A_FIBF_EXECUTE)) /* ----RxEx == ReadOnly */
239 return 1;
240 return 0;
241 }
242
fsdb_create_unique_nname(a_inode * base,const char * suggestion)243 char *fsdb_create_unique_nname (a_inode *base, const char *suggestion)
244 {
245 TCHAR *c;
246 TCHAR tmp[256] = UAEFSDB_BEGINS;
247 int i;
248
249 _tcsncat (tmp, suggestion, 240);
250
251 /* replace the evil ones... */
252 for (i = 0; i < NUM_EVILCHARS; i++)
253 while ((c = _tcschr (tmp, evilchars[i])) != 0)
254 *c = '_';
255
256 while ((c = _tcschr (tmp, '.')) != 0)
257 *c = '_';
258 while ((c = _tcschr (tmp, ' ')) != 0)
259 *c = '_';
260
261 for (;;) {
262 TCHAR *p = build_nname (base->nname, tmp);
263 if (!fsdb_exists (p)) {
264 write_log (_T("unique name: %s\n"), p);
265 return p;
266 }
267 xfree (p);
268 /* tmpnam isn't reentrant and I don't really want to hack configure
269 * right now to see whether tmpnam_r is available... */
270 for (i = 0; i < 8; i++) {
271 tmp[i+8] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[rand () % 63];
272 }
273 }
274 }
275