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 Win32 version.
7   *
8   * Copyright 1997 Mathias Ortmann
9   * Copyright 1999 Bernd Schmidt
10   */
11 
12 #include "sysconfig.h"
13 #include "sysdeps.h"
14 
15 #include "fsdb.h"
16 #include <windows.h>
17 
18 /* these are deadly (but I think allowed on the Amiga): */
19 #define NUM_EVILCHARS 7
20 char evilchars[NUM_EVILCHARS] = { '\\', '*', '?', '\"', '<', '>', '|' };
21 
22 /* Return nonzero for any name we can't create on the native filesystem.  */
fsdb_name_invalid(const char * n)23 int fsdb_name_invalid (const char *n)
24 {
25     int i;
26     char a = n[0];
27     char b = (a == '\0' ? a : n[1]);
28     char c = (b == '\0' ? b : n[2]);
29     char d = (c == '\0' ? c : n[3]);
30     int l = strlen (n);
31 
32     if (a >= 'a' && a <= 'z')
33 	a -= 32;
34     if (b >= 'a' && b <= 'z')
35 	b -= 32;
36     if (c >= 'a' && c <= 'z')
37 	c -= 32;
38 
39     if ((a == 'A' && b == 'U' && c == 'X' && l == 3) /* AUX  */
40 	|| (a == 'C' && b == 'O' && c == 'N' && l == 3) /* CON  */
41 	|| (a == 'P' && b == 'R' && c == 'N' && l == 3) /* PRN  */
42 	|| (a == 'N' && b == 'U' && c == 'L' && l == 3) /* NUL  */
43 	|| (a == 'L' && b == 'P' && c == 'T'  && (d >= '0' && d <= '9') && l == 4)  /* LPT# */
44 	|| (a == 'C' && b == 'O' && c == 'M'  && (d >= '0' && d <= '9') && l == 4)) /* COM# */
45 	return 1;
46 
47     /* spaces and periods at the end are a no-no */
48     i = strlen(n) - 1;
49     if (n[i] == '.' || n[i] == ' ')
50 	return 1;
51 
52     /* these characters are *never* allowed */
53     for (i = 0; i < NUM_EVILCHARS; i++) {
54 	if (strchr (n, evilchars[i]) != 0)
55 	    return 1;
56     }
57 
58     /* the reserved fsdb filename */
59     if (strcmp (n, FSDB_FILE) == 0)
60 	return 1;
61     return 0; /* the filename passed all checks, now it should be ok */
62 }
63 
filesys_parse_mask(uae_u32 mask)64 uae_u32 filesys_parse_mask(uae_u32 mask)
65 {
66     return mask ^ 0xf;
67 }
68 
69 /* For an a_inode we have newly created based on a filename we found on the
70  * native fs, fill in information about this file/directory.  */
fsdb_fill_file_attrs(a_inode * aino)71 void fsdb_fill_file_attrs (a_inode *aino)
72 {
73     int mode;
74 
75     if((mode = GetFileAttributes(aino->nname)) == 0xFFFFFFFF) return;
76 
77     aino->dir = (mode & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
78     aino->amigaos_mode = A_FIBF_EXECUTE | A_FIBF_READ;
79     if (FILE_ATTRIBUTE_ARCHIVE & mode)
80 	aino->amigaos_mode |= A_FIBF_ARCHIVE;
81     if (! (FILE_ATTRIBUTE_READONLY & mode))
82 	aino->amigaos_mode |= A_FIBF_WRITE | A_FIBF_DELETE;
83     aino->amigaos_mode = filesys_parse_mask(aino->amigaos_mode);
84 }
85 
fsdb_set_file_attrs(a_inode * aino,int mask)86 int fsdb_set_file_attrs (a_inode *aino, int mask)
87 {
88     struct stat statbuf;
89     uae_u32 mode=0, tmpmask;
90 
91     tmpmask = filesys_parse_mask(mask);
92 
93     if (stat (aino->nname, &statbuf) == -1)
94 	return ERROR_OBJECT_NOT_AROUND;
95 
96     /* Unix dirs behave differently than AmigaOS ones.  */
97     /* windows dirs go where no dir has gone before...  */
98     if (! aino->dir) {
99 	if ((tmpmask & (A_FIBF_READ | A_FIBF_DELETE)) == 0)
100 	    mode |= FILE_ATTRIBUTE_READONLY;
101 	if (tmpmask & A_FIBF_ARCHIVE)
102 	    mode |= FILE_ATTRIBUTE_ARCHIVE;
103 	else
104 	    mode &= ~FILE_ATTRIBUTE_ARCHIVE;
105 
106 	SetFileAttributes(aino->nname, mode);
107     }
108 
109     aino->amigaos_mode = mask;
110     aino->dirty = 1;
111     return 0;
112 }
113 
114 /* Return nonzero if we can represent the amigaos_mode of AINO within the
115  * native FS.  Return zero if that is not possible.  */
fsdb_mode_representable_p(const a_inode * aino)116 int fsdb_mode_representable_p (const a_inode *aino)
117 {
118     int mask = aino->amigaos_mode;
119     int m1;
120 
121     if (aino->dir)
122 	return aino->amigaos_mode == 0;
123 
124     /* P or S set, or E or R clear, means we can't handle it.  */
125     if (mask & (A_FIBF_SCRIPT | A_FIBF_PURE | A_FIBF_EXECUTE | A_FIBF_READ))
126 	return 0;
127 
128     m1 = A_FIBF_DELETE | A_FIBF_WRITE;
129     /* If it's rwed, we are OK... */
130     if ((mask & m1) == 0)
131 	return 1;
132     /* We can also represent r-e-, by setting the host's readonly flag.  */
133     if ((mask & m1) == m1)
134 	return 1;
135     return 0;
136 }
137 
fsdb_create_unique_nname(a_inode * base,const char * suggestion)138 char *fsdb_create_unique_nname (a_inode *base, const char *suggestion)
139 {
140     char *c;
141     char tmp[256] = "__uae___";
142     int i;
143 
144     strncat (tmp, suggestion, 240);
145 
146     /* replace the evil ones... */
147     for (i=0; i < NUM_EVILCHARS; i++)
148 	while ((c = strchr (tmp, evilchars[i])) != 0)
149 	    *c = '_';
150 
151     while ((c = strchr (tmp, '.')) != 0)
152 	*c = '_';
153     while ((c = strchr (tmp, ' ')) != 0)
154 	*c = '_';
155 
156     for (;;) {
157 	char *p = build_nname (base->nname, tmp);
158 	if (access (p, R_OK) < 0 && errno == ENOENT) {
159 	    write_log ("unique name: %s\n", p);
160 	    return p;
161 	}
162 	free (p);
163 
164 	/* tmpnam isn't reentrant and I don't really want to hack configure
165 	 * right now to see whether tmpnam_r is available...  */
166 	for (i = 0; i < 8; i++) {
167 	    tmp[i+8] = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"[rand () % 63];
168 	}
169     }
170 }
171