]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/codepage.c
Initial revision
[netatalk.git] / etc / afpd / codepage.c
1 /*
2  * Copyright (c) 2000 Adrian Sun
3  * All Rights Reserved. See COPYRIGHT.
4  *
5  * codepage support (based initially on some code from
6  * julian@whistle.com)
7  *
8  * the strategy:
9  * for single-byte maps, the codepage support devolves to a lookup
10  * table for all possible 8-bit values. for double-byte maps, 
11  * the first byte is used as a hash index followed by a linked list of
12  * values.
13  *
14  * the badumap specifies illegal characters. these are 8-bit values
15  * with an associated rule field. here are the rules:
16  *   
17  *
18  * illegal values: 0 is the only illegal value. no translation will
19  * occur in those cases.  
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <syslog.h>
30
31 #include <netatalk/endian.h>
32
33 #include "globals.h"
34 #include "volume.h"
35 #include "codepage.h"
36
37 #define MAPSIZE 256
38
39 /* deal with linked lists */
40 #define CP_INIT(a) (a)->next = (a)->prev = (a)
41 #define CP_ADD(a, b) do { \
42   (b)->next = (a)->next; \
43   (b)->prev = (a); \
44   (a)->next = (b); \
45 } while (0)
46 #define CP_REMOVE(a) do {  \
47   (a)->prev->next = (a)->next; \
48   (a)->next->prev = (a)->prev; \
49 } while (0)
50
51 /* search for stuff */
52 #if 0
53 static __inline__ unsigned char *codepage_find(struct codepage *page,
54                                                unsigned char *from)
55 {
56 }
57 #endif
58
59 static int add_code(struct codepage *page, unsigned char *from,
60                     unsigned char *to)
61 {
62   union codepage_val *ptr;
63
64   if (page->quantum < 1) /* no quantum given. don't do anything */
65     return 1;
66
67   if (page->quantum == 1) {
68     page->map[*from].value = *to;
69     return 0;
70   }
71
72 #if 0
73   if (ptr = codepage_find(page->map, from)) {
74     
75   } else {
76     unsigned char *space;
77     ptr = map[*from].hash;
78
79     space = (unsigned char *) malloc(sizeof(unsigned char)*quantum);
80     if (!ptr->from) {
81     } else {
82     }
83     
84     map[*from].hash
85   }
86 #endif
87 }
88
89 static struct codepage *init_codepage(const int quantum)
90 {
91     struct codepage *cp;
92
93     cp = (struct codepage *) malloc(sizeof(struct codepage));
94     if (!cp)
95       return NULL;
96
97     if ((cp->map = (union codepage_val *)
98          calloc(MAPSIZE, sizeof(union codepage_val))) == NULL) {
99       free(cp);
100       return NULL;
101     }
102
103     cp->quantum = quantum;
104     return cp;
105 }
106
107
108 static void free_codepage(struct codepage *cp)
109 {
110   int i;
111
112   if (!cp)
113     return;
114
115   if (cp->map) {
116     if (cp->quantum > 1) {
117       /* deal with any linked lists that may exist */
118       for (i = 0; i < MAPSIZE; i++) {
119         struct codepage_hash *ptr, *h;
120         
121         h = &cp->map[i].hash; /* we don't free this one */
122         while ((ptr = h->prev) != h) {
123           CP_REMOVE(ptr);
124           free(ptr);
125         }
126       }
127     }
128     free(cp->map);
129   }
130   free(cp);
131 }
132
133
134
135 /* this is used by both codepages and generic mapping utilities. we
136  * allocate enough space to map all 8-bit characters if necessary.
137  * for double-byte mappings, we just use the table as a hash lookup.
138  * if we don't match, we don't convert.
139  */
140 int codepage_init(struct vol *vol, const int rules, 
141                   const int quantum)
142 {
143   if ((rules & CODEPAGE_RULE_MTOU) && !vol->v_utompage) {
144     vol->v_utompage = init_codepage(quantum);
145     if (!vol->v_utompage)
146       return -1;
147   }
148
149   if ((rules & CODEPAGE_RULE_UTOM) && !vol->v_mtoupage) {
150     vol->v_mtoupage = init_codepage(quantum);
151     if (!vol->v_mtoupage) {
152       goto err_utompage;
153     }
154   }
155
156   if ((rules & CODEPAGE_RULE_BADU)  && !vol->v_badumap) {
157     vol->v_badumap = init_codepage(quantum);
158     if (!vol->v_badumap)
159       goto err_mtoupage;
160   }
161   return 0;
162
163 err_mtoupage:
164     free_codepage(vol->v_mtoupage);
165     vol->v_mtoupage = NULL;
166
167 err_utompage:
168     free_codepage(vol->v_utompage);
169     vol->v_utompage = NULL;
170     return -1;
171 }
172
173 void codepage_free(struct vol *vol)
174 {
175   if (vol->v_utompage) {
176     free_codepage(vol->v_utompage);
177     vol->v_utompage = NULL;
178   }
179
180   if (vol->v_mtoupage) {
181     free_codepage(vol->v_mtoupage);
182     vol->v_mtoupage = NULL;
183   }
184
185   if (vol->v_badumap) {
186     free_codepage(vol->v_badumap);
187     vol->v_badumap = NULL;
188   }
189 }
190
191
192 int codepage_read(struct vol *vol, const char *path)
193 {
194   unsigned char buf[CODEPAGE_FILE_HEADER_SIZE], *cur;
195   u_int16_t id;
196   int fd, i, quantum, rules;
197   
198   if ((fd = open(path, O_RDONLY)) < 0) {
199     syslog(LOG_ERR, "%s: failed to open codepage", path);
200     return -1;
201   }
202   
203   /* Read the codepage file header. */
204   if(read(fd, buf, sizeof(buf)) != sizeof(buf)) {
205     syslog( LOG_ERR, "%s: failed to read codepage header", path);
206     goto codepage_fail;
207   }
208
209   /* Check the file id */
210   cur = buf;
211   memcpy(&id, cur, sizeof(id));
212   cur += sizeof(id);
213   id = ntohs(id);
214   if (id != CODEPAGE_FILE_ID) {
215       syslog( LOG_ERR, "%s: not a codepage", path);
216       goto codepage_fail;
217   } 
218
219   /* check the version number */
220   if (*cur++ != CODEPAGE_FILE_VERSION) {
221       syslog( LOG_ERR, "%s: codepage version not supported", path);
222       goto codepage_fail;
223   } 
224
225   /* find out the data quantum size. default to 1 if nothing's given. */
226   quantum = *cur ? *cur : 1;
227   cur++;
228   
229   /* rules used in this file. */
230   rules = *cur++;
231
232   if (codepage_init(vol, rules, quantum) < 0) {
233     syslog( LOG_ERR, "%s: Unable to allocate memory", path);
234     goto codepage_fail;
235   }
236
237   /* offset to data */
238
239   /* skip to the start of the data */
240   memcpy(&id, cur , sizeof(id));
241   id = ntohs(id);
242   lseek(fd, id, SEEK_SET);
243
244   /* mtoupage is the the equivalent of samba's unix2dos. utompage is
245    * the equivalent of dos2unix. it's a little confusing due to a
246    * desire to match up with mtoupath and utompath. 
247    * NOTE: we allow codepages to specify 7-bit mappings if they want. 
248    */
249   i = 1 + 2*quantum;
250   while (read(fd, buf, i) == i) {
251     if (*buf & CODEPAGE_RULE_MTOU) {
252       if (add_code(vol->v_mtoupage, buf + 1, buf + 1 + quantum) < 0) {
253         syslog(LOG_ERR, "unable to allocate memory for mtoupage");
254         break;
255       }
256     }
257
258     if (*buf & CODEPAGE_RULE_UTOM) {
259       if (add_code(vol->v_utompage, buf + 1 + quantum, buf + 1) < 0) {
260         syslog(LOG_ERR, "unable to allocate memory for utompage");
261         break;
262       }
263     }
264       
265     /* we only look at the first character here. if we need to 
266      * do so, we can always use the quantum to expand the 
267      * available flags. */
268     if (*buf & CODEPAGE_RULE_BADU) 
269       vol->v_badumap->map[*(buf + 1)].value = *(buf + 1 + quantum);
270   }
271   close(fd);
272   return 0;
273
274 codepage_fail:
275   close(fd);
276   return -1;
277 }