]> arthur.barton.de Git - netatalk.git/blob - libatalk/util/volinfo.c
dbd now does many things it should do in the end.
[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         path[pos-path]=0;
122         if ((pos = strrchr(path, '/'))) {
123             path[pos-path]=0;
124             strlcat(path, subdir, maxlen);
125         }
126         else {
127             return NULL;
128         }
129     }
130
131     path[pos-path] = '/';
132     path[pos-path+1] = 0;
133
134     return path;
135 }
136
137 static char * make_path_absolute(char *path, size_t bufsize)
138 {
139     struct      stat st;
140     char        savecwd[MAXPATHLEN];
141     char        abspath[MAXPATHLEN];
142     char        *p;
143
144     if (stat(path, &st) != 0) {
145         return NULL;
146     }
147
148     strlcpy (abspath, path, sizeof(abspath));
149
150     if (!S_ISDIR(st.st_mode)) {
151         if (NULL == (p=strrchr(abspath, '/')) )
152             return NULL;
153         *p = '\0';
154     }
155
156     if (!getcwd(savecwd, sizeof(savecwd)) || chdir(abspath) < 0)        
157         return NULL;
158
159     if (!getcwd(abspath, sizeof(abspath)) || chdir (savecwd) < 0)
160         return NULL;
161         
162     
163     if (strlen(abspath) > bufsize)
164         return NULL;
165
166     strlcpy(path, abspath, bufsize);
167
168     return path;
169 }
170
171 static char * find_volumeroot(char *path, size_t maxlen)
172 {
173     char *volume = make_path_absolute(path, maxlen);
174         
175     if (volume == NULL)
176        return NULL;
177
178     if (NULL == (find_in_path(volume, "/.AppleDesktop", maxlen)) )
179        return NULL;
180
181     return volume;
182 }
183
184 int vol_load_charsets( struct volinfo *vol)
185 {
186     if ( (charset_t) -1 == ( vol->v_maccharset = add_charset(vol->v_maccodepage)) ) {
187         fprintf( stderr, "Setting codepage %s as Mac codepage failed", vol->v_maccodepage);
188         return (-1);
189     }
190
191     if ( (charset_t) -1 == ( vol->v_volcharset = add_charset(vol->v_volcodepage)) ) {
192         fprintf( stderr, "Setting codepage %s as volume codepage failed", vol->v_volcodepage);
193         return (-1);
194     }
195
196     return 0;
197 }
198
199 static int parse_options (char *buf, int *flags, const _vol_opt_name* options)
200 {
201     char *p, *q;
202     const _vol_opt_name *op;
203
204     q = p = buf; 
205
206     while ( *p != '\0') {
207         if (*p == ' ') {
208             *p = '\0';
209             op = options;
210             for (;op->name; op++) {
211                 if ( !strcmp(op->name, q )) {
212                     *flags |= op->option;
213                     break;
214                 }
215             }
216             q = p+1;
217         }
218         p++;
219     }
220
221     return 0;
222
223             
224
225
226 static int parseline ( char *buf, struct volinfo *vol)
227 {
228     char *value;
229     size_t len;
230     int  option=-1;
231     const _info_option  *p  = &info_options[0];
232
233     if (NULL == ( value = strchr(buf, ':')) )
234         return 1;
235
236     *value = '\0';
237     value++;
238
239     if ( 0 == (len = strlen(value)) )
240         return 0;
241
242     if (value[len-1] == '\n')
243         value[len-1] = '\0';
244
245     for (;p->name; p++) {
246         if ( !strcmp(p->name, buf )) {
247             option=p->type;
248             break;
249         }
250     }
251
252     switch (option) {
253       case MAC_CHARSET:
254         if ((vol->v_maccodepage = strdup(value)) == NULL) {
255             fprintf (stderr, "strdup: %s", strerror(errno));
256             return -1;
257         }
258         break;
259       case VOL_CHARSET:
260         if ((vol->v_volcodepage = strdup(value)) == NULL) {
261             fprintf (stderr, "strdup: %s", strerror(errno));
262             return -1;
263         }
264         break;
265       case CNIDBACKEND:
266         if ((vol->v_cnidscheme = strdup(value)) == NULL) {
267             fprintf (stderr, "strdup: %s", strerror(errno));
268             return -1;
269         }
270         break;
271       case CNIDDBDHOST:
272         if ((vol->v_dbd_host = strdup(value)) == NULL) {
273             fprintf (stderr, "strdup: %s", strerror(errno));
274             return -1;
275         }
276         break;
277       case CNIDDBDPORT:
278         vol->v_dbd_port = atoi(value);
279         break;
280       case CNID_DBPATH:
281         if ((vol->v_dbpath = strdup(value)) == NULL) {
282             fprintf (stderr, "strdup: %s", strerror(errno));
283             return -1;
284         }
285         break;
286       case ADOUBLE_VER:
287         if (strcasecmp(value, "v1") == 0) {
288             vol->v_adouble = AD_VERSION1;
289             vol->ad_path = ad_path;
290         }
291 #if AD_VERSION == AD_VERSION2
292         else if (strcasecmp(value, "v2") == 0) {
293             vol->ad_path = ad_path;
294             vol->v_adouble = AD_VERSION2;
295         }
296         else if (strcasecmp(value, "osx") == 0) {
297             vol->v_adouble = AD_VERSION2_OSX;
298             vol->ad_path = ad_path_osx;
299         }
300 #endif
301         else  {
302             fprintf (stderr, "unknown adouble version: %s, %s", buf, value);
303             return -1;
304         }
305         break;
306       case VOLUME_OPTS:
307         parse_options(value, &vol->v_flags, &vol_opt_names[0]);
308         break;
309       case VOLCASEFOLD:
310         parse_options(value, &vol->v_casefold, &vol_opt_casefold[0]);
311         break;
312       default:
313         fprintf (stderr, "unknown volume information: %s, %s", buf, value);
314         return (-1);
315         break;
316     }
317         
318     return 0;
319 }
320     
321
322 int loadvolinfo (char *path, struct volinfo *vol)
323 {
324
325     char   volinfofile[MAXPATHLEN];
326     char   buf[MAXPATHLEN];
327     struct flock lock;
328     int    fd;
329     FILE   *fp;
330
331     if ( !path || !vol)
332         return -1;
333
334     memset(vol, 0, sizeof(struct volinfo));
335     strlcpy(volinfofile, path, sizeof(volinfofile));
336
337     /* volinfo file is in .AppleDesktop */ 
338     if ( NULL == find_volumeroot(volinfofile, sizeof(volinfofile)))
339         return -1;
340
341     if ((vol->v_path = strdup(volinfofile)) == NULL ) {
342         fprintf (stderr, "strdup: %s", strerror(errno));
343         return (-1);
344     }
345     strlcat(volinfofile, ".AppleDesktop/", sizeof(volinfofile));
346     strlcat(volinfofile, VOLINFOFILE, sizeof(volinfofile));
347
348     /* open the file read only */
349     if ( NULL == (fp = fopen( volinfofile, "r")) )  {
350         fprintf (stderr, "error opening volinfo (%s): %s", volinfofile, strerror(errno));
351         return (-1);
352     }
353     fd = fileno(fp); 
354
355     /* try to get a read lock */ 
356     lock.l_start  = 0;
357     lock.l_whence = SEEK_SET;
358     lock.l_len    = 0;
359     lock.l_type   = F_RDLCK;
360
361     /* wait for read lock */
362     if (fcntl(fd, F_SETLKW, &lock) < 0) {
363         fclose(fp);
364         return (-1);
365     }
366
367     /* read the file */
368     while (NULL != fgets(buf, sizeof(buf), fp)) {
369         parseline(buf, vol);
370     }
371
372     /* unlock file */
373     lock.l_type = F_UNLCK;
374     fcntl(fd, F_SETLK, &lock);
375
376     /* Translate vol options to ad options like afp/volume.c does it */
377     vol->v_ad_options = 0;
378     if ((vol->v_flags & AFPVOL_NODEV))
379         vol->v_ad_options |= ADVOL_NODEV;
380     if ((vol->v_flags & AFPVOL_CACHE))
381         vol->v_ad_options |= ADVOL_CACHE;
382     if ((vol->v_flags & AFPVOL_UNIX_PRIV))
383         vol->v_ad_options |= ADVOL_UNIXPRIV;
384     if ((vol->v_flags & AFPVOL_INV_DOTS))
385         vol->v_ad_options |= ADVOL_INVDOTS;
386
387     fclose(fp);
388     return 0;
389 }