]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/volinfo.c
Sync volume options with volinfo stuff
[netatalk.git] / libatalk / util / volinfo.c
1 /*
2    This program is free software; you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation; either version 2 of the License, or
5    (at your option) any later version.
6
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15
16    .volinfo file handling, command line utilities
17    copyright Bjoern Fernhomberg, 2004
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif /* HAVE_CONFIG_H */
23
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #ifdef HAVE_STRINGS_H
31 #include <strings.h>
32 #endif
33 #ifdef STDC_HEADERS
34 #include <string.h>
35 #endif
36 #include <sys/param.h>
37
38 #include <atalk/adouble.h>
39 #include <atalk/util.h>
40 #include <atalk/logger.h>
41 #include <atalk/volinfo.h>
42 #ifdef CNID_DB
43 #include <atalk/cnid.h>
44 #endif /* CNID_DB*/
45
46 #define MAC_CHARSET 0
47 #define VOL_CHARSET 1
48 #define ADOUBLE_VER 2
49 #define CNIDBACKEND 3
50 #define CNIDDBDHOST 4
51 #define CNIDDBDPORT 5
52 #define CNID_DBPATH 6
53 #define VOLUME_OPTS 7
54 #define VOLCASEFOLD 8
55
56 typedef struct _info_option {
57     const char *name;
58     int type;
59 } _info_option;
60
61 static const _info_option info_options[] = {
62     {"MAC_CHARSET", MAC_CHARSET},
63     {"VOL_CHARSET", VOL_CHARSET},
64     {"ADOUBLE_VER", ADOUBLE_VER},
65     {"CNIDBACKEND", CNIDBACKEND},
66     {"CNIDDBDHOST", CNIDDBDHOST},
67     {"CNIDDBDPORT", CNIDDBDPORT},
68     {"CNID_DBPATH", CNID_DBPATH},
69     {"VOLUME_OPTS", VOLUME_OPTS},
70     {"VOLCASEFOLD", VOLCASEFOLD},
71     {NULL, 0}
72 };
73
74 typedef struct _vol_opt_name {
75     const u_int32_t option;
76     const char      *name;
77 } _vol_opt_name;
78
79 static const _vol_opt_name vol_opt_names[] = {
80     {AFPVOL_A2VOL,      "PRODOS"},      /* prodos volume */
81     {AFPVOL_CRLF,       "CRLF"},        /* cr/lf translation */
82     {AFPVOL_NOADOUBLE,  "NOADOUBLE"},   /* don't create .AppleDouble by default */
83     {AFPVOL_RO,         "READONLY"},    /* read-only volume */
84     {AFPVOL_MSWINDOWS,  "MSWINDOWS"},   /* deal with ms-windows yuckiness. this is going away. */
85     {AFPVOL_NOHEX,      "NOHEX"},       /* don't do :hex translation */
86     {AFPVOL_USEDOTS,    "USEDOTS"},     /* use real dots */
87     {AFPVOL_LIMITSIZE,  "LIMITSIZE"},   /* limit size for older macs */
88     {AFPVOL_MAPASCII,   "MAPASCII"},    /* map the ascii range as well */
89     {AFPVOL_DROPBOX,    "DROPBOX"},     /* dropkludge dropbox support */
90     {AFPVOL_NOFILEID,   "NOFILEID"},    /* don't advertise createid resolveid and deleteid calls */
91     {AFPVOL_NOSTAT,     "NOSTAT"},      /* advertise the volume even if we can't stat() it
92                                          * maybe because it will be mounted later in preexec */
93     {AFPVOL_UNIX_PRIV,  "UNIXPRIV"},    /* support unix privileges */
94     {AFPVOL_NODEV,      "NODEV"},       /* always use 0 for device number in cnid calls */
95     {AFPVOL_CASEINSEN,  "CASEINSENSITIVE"}, /* volume is case insensitive */
96     {AFPVOL_EILSEQ,     "ILLEGALSEQ"},  /* encode illegal sequence */
97     {AFPVOL_CACHE,      "CACHEID"},     /* Use adouble v2 CNID caching, default don't use it */
98     {AFPVOL_INV_DOTS,   "INVISIBLEDOTS"}, 
99     {AFPVOL_EXT_ATTRS,  "EXT_ATTRS"},   /* Vol supports Extened Attributes */
100     {AFPVOL_ACLS,       "ACLS"},        /* Vol supports ACLs */
101     {0, NULL}
102 };
103
104 static const _vol_opt_name vol_opt_casefold[] = {
105     {AFPVOL_MTOUUPPER,  "MTOULOWER"},
106     {AFPVOL_MTOULOWER,  "MTOULOWER"},
107     {AFPVOL_UTOMUPPER,  "UTOMUPPER"},
108     {AFPVOL_UTOMLOWER,  "UTOMLOWER"},
109     {0, NULL}
110 };
111
112 static char* find_in_path( char *path, char *subdir, size_t maxlen)
113 {
114     char        *pos;
115     struct stat st;
116
117     strlcat(path, subdir, maxlen);
118     pos = strrchr(path, '/');
119
120     while ( stat(path, &st) != 0) {
121 #ifdef DEBUG
122         fprintf(stderr, "searching in path %s\n", path);
123 #endif
124         path[pos-path]=0;
125         if ((pos = strrchr(path, '/'))) {
126             path[pos-path]=0;
127             strlcat(path, subdir, maxlen);
128         }
129         else {
130             return NULL;
131         }
132     }
133
134     path[pos-path] = '/';
135     path[pos-path+1] = 0;
136 #ifdef DEBUG
137     fprintf(stderr, "%s path %s\n", subdir, path);
138 #endif
139     return path;
140 }
141
142 static char * make_path_absolute(char *path, size_t bufsize)
143 {
144     struct      stat st;
145     char        savecwd[MAXPATHLEN];
146     char        abspath[MAXPATHLEN];
147     char        *p;
148
149     if (stat(path, &st) != 0) {
150         return NULL;
151     }
152
153     strlcpy (abspath, path, sizeof(abspath));
154
155     if (!S_ISDIR(st.st_mode)) {
156         if (NULL == (p=strrchr(abspath, '/')) )
157             return NULL;
158         *p = '\0';
159     }
160
161     if (!getcwd(savecwd, sizeof(savecwd)) || chdir(abspath) < 0)        
162         return NULL;
163
164     if (!getcwd(abspath, sizeof(abspath)) || chdir (savecwd) < 0)
165         return NULL;
166         
167     
168     if (strlen(abspath) > bufsize)
169         return NULL;
170
171     strlcpy(path, abspath, bufsize);
172
173     return path;
174 }
175
176 static char * find_volumeroot(char *path, size_t maxlen)
177 {
178     char *volume = make_path_absolute(path, maxlen);
179         
180     if (volume == NULL)
181        return NULL;
182
183     if (NULL == (find_in_path(volume, "/.AppleDesktop", maxlen)) )
184        return NULL;
185
186     return volume;
187 }
188
189 int vol_load_charsets( struct volinfo *vol)
190 {
191     if ( (charset_t) -1 == ( vol->v_maccharset = add_charset(vol->v_maccodepage)) ) {
192         fprintf( stderr, "Setting codepage %s as Mac codepage failed", vol->v_maccodepage);
193         return (-1);
194     }
195
196     if ( (charset_t) -1 == ( vol->v_volcharset = add_charset(vol->v_volcodepage)) ) {
197         fprintf( stderr, "Setting codepage %s as volume codepage failed", vol->v_volcodepage);
198         return (-1);
199     }
200
201     return 0;
202 }
203
204 static int parse_options (char *buf, int *flags, const _vol_opt_name* options)
205 {
206     char *p, *q;
207     const _vol_opt_name *op;
208
209     q = p = buf; 
210
211     while ( *p != '\0') {
212         if (*p == ' ') {
213             *p = '\0';
214             op = options;
215             for (;op->name; op++) {
216                 if ( !strcmp(op->name, q )) {
217                     *flags |= op->option;
218                     break;
219                 }
220             }
221             q = p+1;
222         }
223         p++;
224     }
225
226     return 0;
227
228             
229
230
231 static int parseline ( char *buf, struct volinfo *vol)
232 {
233     char *value;
234     size_t len;
235     int  option=-1;
236     const _info_option  *p  = &info_options[0];
237
238     if (NULL == ( value = strchr(buf, ':')) )
239         return 1;
240
241     *value = '\0';
242     value++;
243
244     if ( 0 == (len = strlen(value)) )
245         return 0;
246
247     if (value[len-1] == '\n')
248         value[len-1] = '\0';
249
250     for (;p->name; p++) {
251         if ( !strcmp(p->name, buf )) {
252             option=p->type;
253             break;
254         }
255     }
256
257     switch (option) {
258       case MAC_CHARSET:
259         if ((vol->v_maccodepage = strdup(value)) == NULL) {
260             fprintf (stderr, "strdup: %s", strerror(errno));
261             return -1;
262         }
263         break;
264       case VOL_CHARSET:
265         if ((vol->v_volcodepage = strdup(value)) == NULL) {
266             fprintf (stderr, "strdup: %s", strerror(errno));
267             return -1;
268         }
269         break;
270       case CNIDBACKEND:
271         if ((vol->v_cnidscheme = strdup(value)) == NULL) {
272             fprintf (stderr, "strdup: %s", strerror(errno));
273             return -1;
274         }
275         break;
276       case CNIDDBDHOST:
277         if ((vol->v_dbd_host = strdup(value)) == NULL) {
278             fprintf (stderr, "strdup: %s", strerror(errno));
279             return -1;
280         }
281         break;
282       case CNIDDBDPORT:
283         vol->v_dbd_port = atoi(value);
284         break;
285       case CNID_DBPATH:
286         if ((vol->v_dbpath = strdup(value)) == NULL) {
287             fprintf (stderr, "strdup: %s", strerror(errno));
288             return -1;
289         }
290         break;
291       case ADOUBLE_VER:
292         if (strcasecmp(value, "v1") == 0) {
293             vol->v_adouble = AD_VERSION1;
294             vol->ad_path = ad_path;
295         }
296 #if AD_VERSION == AD_VERSION2
297         else if (strcasecmp(value, "v2") == 0) {
298             vol->ad_path = ad_path;
299             vol->v_adouble = AD_VERSION2;
300         }
301         else if (strcasecmp(value, "osx") == 0) {
302             vol->v_adouble = AD_VERSION2_OSX;
303             vol->ad_path = ad_path_osx;
304         }
305 #endif
306         else  {
307             fprintf (stderr, "unknown adouble version: %s, %s", buf, value);
308             return -1;
309         }
310         break;
311       case VOLUME_OPTS:
312         parse_options(value, &vol->v_flags, &vol_opt_names[0]);
313         break;
314       case VOLCASEFOLD:
315         parse_options(value, &vol->v_casefold, &vol_opt_casefold[0]);
316         break;
317       default:
318         fprintf (stderr, "unknown volume information: %s, %s", buf, value);
319         return (-1);
320         break;
321     }
322 #ifdef DEBUG
323     printf ("volume information: %s, %s", buf, value);
324 #endif
325         
326     return 0;
327 }
328     
329
330 int loadvolinfo (char *path, struct volinfo *vol)
331 {
332
333     char   volinfofile[MAXPATHLEN];
334     char   buf[MAXPATHLEN];
335     struct flock lock;
336     int    fd;
337     FILE   *fp;
338
339     if ( !path || !vol)
340         return -1;
341
342     memset(vol, 0, sizeof(struct volinfo));
343     strlcpy(volinfofile, path, sizeof(volinfofile));
344
345     /* volinfo file is in .AppleDesktop */ 
346     if ( NULL == find_volumeroot(volinfofile, sizeof(volinfofile)))
347         return -1;
348
349     if ((vol->v_path = strdup(volinfofile)) == NULL ) {
350         fprintf (stderr, "strdup: %s", strerror(errno));
351         return (-1);
352     }
353     strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
354     strlcat(volinfofile, VOLINFOFILE, sizeof(volinfofile));
355
356     /* open the file read only */
357     if ( NULL == (fp = fopen( volinfofile, "r")) )  {
358         fprintf (stderr, "error opening volinfo (%s): %s", volinfofile, strerror(errno));
359         return (-1);
360     }
361     fd = fileno(fp); 
362
363     /* try to get a read lock */ 
364     lock.l_start  = 0;
365     lock.l_whence = SEEK_SET;
366     lock.l_len    = 0;
367     lock.l_type   = F_RDLCK;
368
369     /* wait for read lock */
370     if (fcntl(fd, F_SETLKW, &lock) < 0) {
371         fclose(fp);
372         return (-1);
373     }
374
375     /* read the file */
376     while (NULL != fgets(buf, sizeof(buf), fp)) {
377         parseline(buf, vol);
378     }
379
380     /* unlock file */
381     lock.l_type = F_UNLCK;
382     fcntl(fd, F_SETLK, &lock);
383
384     fclose(fp);
385     return 0;
386 }