~ubuntu-branches/debian/lenny/netatalk/lenny

« back to all changes in this revision

Viewing changes to etc/afpd/volume.c

  • Committer: Bazaar Package Importer
  • Author(s): Ante Karamatic
  • Date: 2005-10-07 13:46:11 UTC
  • mfrom: (1.1.2 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20051007134611-r07qa2g67xwkp2if
Tags: 2.0.3-1ubuntu1
* debian/netatalk.init
  - run cnid_metad if CNID_METAD_RUN=yes

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * $Id: volume.c,v 1.36.2.7 2003/11/18 21:49:41 bfernhomberg Exp $
 
2
 * $Id: volume.c,v 1.51.2.7.2.33.2.5 2005/04/24 22:26:31 didg Exp $
3
3
 *
4
4
 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5
5
 * All Rights Reserved.  See COPYRIGHT.
9
9
#include "config.h"
10
10
#endif /* HAVE_CONFIG_H */
11
11
 
12
 
#include <sys/time.h>
13
 
#include <atalk/logger.h>
14
 
#include <sys/types.h>
15
 
#include <sys/stat.h>
16
 
#include <sys/param.h>
17
 
#include <sys/socket.h>
18
 
#include <netinet/in.h>
19
 
#include <arpa/inet.h>
20
 
#include <netatalk/endian.h>
21
 
#include <atalk/asp.h>
22
 
#include <atalk/dsi.h>
23
 
#include <atalk/adouble.h>
24
 
#include <atalk/afp.h>
25
 
#include <atalk/util.h>
26
 
#ifdef CNID_DB
27
 
#include <atalk/cnid.h>
28
 
#endif /* CNID_DB*/
29
 
#include <dirent.h>
30
 
#ifdef HAVE_FCNTL_H
31
 
#include <fcntl.h>
32
 
#endif /* HAVE_FCNTL_H */
33
12
#include <stdio.h>
34
13
#include <stdlib.h>
35
14
#include <ctype.h>
36
 
 
 
15
#include <dirent.h>
 
16
#include <pwd.h>
 
17
#include <grp.h>
 
18
#include <utime.h>
 
19
#include <errno.h>
 
20
#ifdef HAVE_STRINGS_H
 
21
#include <strings.h>
 
22
#endif
37
23
/* STDC check */
38
24
#if STDC_HEADERS
39
25
#include <string.h>
48
34
#define memmove(d,s,n) bcopy ((s), (d), (n))
49
35
#endif /* ! HAVE_MEMCPY */
50
36
#endif /* STDC_HEADERS */
51
 
 
52
 
#include <pwd.h>
53
 
#include <grp.h>
54
 
#include <utime.h>
55
 
#include <errno.h>
56
 
 
 
37
#include <sys/param.h>
 
38
#include <sys/socket.h>
 
39
#include <netinet/in.h>
 
40
#include <arpa/inet.h>
 
41
#include <atalk/asp.h>
 
42
#include <atalk/dsi.h>
 
43
#include <atalk/adouble.h>
 
44
#include <atalk/afp.h>
 
45
#include <atalk/util.h>
 
46
#include <atalk/logger.h>
 
47
#ifdef CNID_DB
 
48
#include <atalk/cnid.h>
 
49
#endif /* CNID_DB*/
 
50
 
 
51
#include "globals.h"
57
52
#include "directory.h"
58
53
#include "file.h"
59
54
#include "volume.h"
60
 
#include "globals.h"
61
55
#include "unix.h"
62
56
 
 
57
extern int afprun(int root, char *cmd, int *outfd);
 
58
 
63
59
#ifndef MIN
64
60
#define MIN(a, b) ((a) < (b) ? (a) : (b))
65
61
#endif /* ! MIN */
75
71
#endif /* BYTE_ORDER == BIG_ENDIAN */
76
72
#endif /* ! NO_LARGE_VOL_SUPPORT */
77
73
 
78
 
static struct vol *volumes = NULL;
79
 
static int              lastvid = 0;
80
 
#ifndef CNID_DB
 
74
static struct vol *Volumes = NULL;
 
75
static u_int16_t        lastvid = 0;
81
76
static char             *Trash = "\02\024Network Trash Folder";
82
 
#endif /* CNID_DB */
83
 
static struct extmap    *extmap = NULL, *defextmap = NULL;
84
 
static int              extmap_cnt;
 
77
 
 
78
static struct extmap    *Extmap = NULL, *Defextmap = NULL;
 
79
static int              Extmap_cnt;
 
80
static void             free_extmap(void);
85
81
 
86
82
#define VOLOPT_ALLOW      0  /* user allow list */
87
83
#define VOLOPT_DENY       1  /* user deny list */
88
84
#define VOLOPT_RWLIST     2  /* user rw list */
89
85
#define VOLOPT_ROLIST     3  /* user ro list */
90
 
#define VOLOPT_CODEPAGE   4  /* codepage */
91
 
#define VOLOPT_PASSWORD   5  /* volume password */
92
 
#define VOLOPT_CASEFOLD   6  /* character case mangling */
93
 
#define VOLOPT_FLAGS      7  /* various flags */
94
 
#define VOLOPT_DBPATH     8  /* path to database */
95
 
#define VOLOPT_MAPCHARS   9  /* does mtou and utom mappings. syntax:
 
86
#define VOLOPT_PASSWORD   4  /* volume password */
 
87
#define VOLOPT_CASEFOLD   5  /* character case mangling */
 
88
#define VOLOPT_FLAGS      6  /* various flags */
 
89
#define VOLOPT_DBPATH     7  /* path to database */
 
90
#define VOLOPT_MAPCHARS   8  /* does mtou and utom mappings. syntax:
96
91
m and u can be double-byte hex
97
92
strings if necessary.
98
93
m=u -> map both ways
102
97
  ~u  -> make u illegal only as the first
103
98
  part of a double-byte character.
104
99
  */
105
 
#define VOLOPT_VETO      10  /* list of veto filespec */
106
 
 
 
100
#define VOLOPT_VETO          10  /* list of veto filespec */
 
101
#define VOLOPT_PREEXEC       11  /* preexec command */
 
102
#define VOLOPT_ROOTPREEXEC   12  /* root preexec command */
 
103
 
 
104
#define VOLOPT_POSTEXEC      13  /* postexec command */
 
105
#define VOLOPT_ROOTPOSTEXEC  14  /* root postexec command */
 
106
 
 
107
#define VOLOPT_ENCODING      15  /* mac encoding (pre OSX)*/
 
108
#define VOLOPT_MACCHARSET    16
 
109
#define VOLOPT_CNIDSCHEME    17
 
110
#define VOLOPT_ADOUBLE       18  /* adouble version */
107
111
#ifdef FORCE_UIDGID
108
112
#warning UIDGID
109
113
#include "uid.h"
110
114
 
111
 
#define VOLOPT_FORCEUID  11  /* force uid for username x */
112
 
#define VOLOPT_FORCEGID  12  /* force gid for group x */
113
 
#define VOLOPT_UMASK     13
114
 
#define VOLOPT_MAX       13
115
 
#else /* normally, there are only 9 possible options */
116
 
#define VOLOPT_UMASK     11
117
 
#define VOLOPT_MAX       11
 
115
#define VOLOPT_FORCEUID  19  /* force uid for username x */
 
116
#define VOLOPT_FORCEGID  20  /* force gid for group x */
 
117
#define VOLOPT_UMASK     21
 
118
#else 
 
119
#define VOLOPT_UMASK     19
118
120
#endif /* FORCE_UIDGID */
119
121
 
 
122
#define VOLOPT_MAX       (VOLOPT_UMASK +1)
 
123
 
120
124
#define VOLOPT_NUM        (VOLOPT_MAX + 1)
121
125
 
122
126
#define VOLPASSLEN  8
127
131
      int i_value;
128
132
  };
129
133
 
 
134
typedef struct _special_folder {
 
135
        const char *name;
 
136
        int precreate;
 
137
        mode_t mode;
 
138
        int hide;
 
139
} _special_folder;
 
140
 
 
141
static const _special_folder special_folders[] = {
 
142
  {"Network Trash Folder",     1,  0777,  1},
 
143
  {"Temporary Items",          1,  0777,  1},
 
144
  {".AppleDesktop",            1,  0777,  0},
 
145
#if 0
 
146
  {"TheFindByContentFolder",   0,     0,  1},
 
147
  {"TheVolumeSettingsFolder",  0,     0,  1},
 
148
#endif
 
149
  {NULL, 0, 0, 0}};
 
150
 
 
151
typedef struct _volopt_name {
 
152
        const u_int32_t option;
 
153
        const char      *name;
 
154
} _vol_opt_name;
 
155
 
 
156
static const _vol_opt_name vol_opt_names[] = {
 
157
    {AFPVOL_A2VOL,      "PRODOS"},      /* prodos volume */
 
158
    {AFPVOL_CRLF,       "CRLF"},        /* cr/lf translation */
 
159
    {AFPVOL_NOADOUBLE,  "NOADOUBLE"},   /* don't create .AppleDouble by default */
 
160
    {AFPVOL_RO,         "READONLY"},    /* read-only volume */
 
161
    {AFPVOL_MSWINDOWS,  "MSWINDOWS"},   /* deal with ms-windows yuckiness. this is going away. */
 
162
    {AFPVOL_NOHEX,      "NOHEX"},       /* don't do :hex translation */
 
163
    {AFPVOL_USEDOTS,    "USEDOTS"},     /* use real dots */
 
164
    {AFPVOL_LIMITSIZE,  "LIMITSIZE"},   /* limit size for older macs */
 
165
    {AFPVOL_MAPASCII,   "MAPASCII"},    /* map the ascii range as well */
 
166
    {AFPVOL_DROPBOX,    "DROPBOX"},     /* dropkludge dropbox support */
 
167
    {AFPVOL_NOFILEID,   "NOFILEID"},    /* don't advertise createid resolveid and deleteid calls */
 
168
    {AFPVOL_NOSTAT,     "NOSTAT"},      /* advertise the volume even if we can't stat() it
 
169
                                         * maybe because it will be mounted later in preexec */
 
170
    {AFPVOL_UNIX_PRIV,  "UNIXPRIV"},    /* support unix privileges */
 
171
    {AFPVOL_NODEV,      "NODEV"},       /* always use 0 for device number in cnid calls */
 
172
    {0, NULL}
 
173
};
 
174
 
 
175
static const _vol_opt_name vol_opt_casefold[] = {
 
176
    {AFPVOL_MTOUUPPER,  "MTOULOWER"},
 
177
    {AFPVOL_MTOULOWER,  "MTOULOWER"},
 
178
    {AFPVOL_UTOMUPPER,  "UTOMUPPER"},
 
179
    {AFPVOL_UTOMLOWER,  "UTOMLOWER"},
 
180
    {0, NULL}
 
181
};
 
182
 
 
183
static void handle_special_folders (const struct vol *);
 
184
static int savevoloptions (const struct vol *);
 
185
 
130
186
static __inline__ void volfree(struct vol_option *options,
131
187
                               const struct vol_option *save)
132
188
{
147
203
 
148
204
 
149
205
/* handle variable substitutions. here's what we understand:
 
206
 * $b   -> basename of path
150
207
 * $c   -> client ip/appletalk address
 
208
 * $d   -> volume pathname on server
151
209
 * $f   -> full name (whatever's in the gecos field)
152
210
 * $g   -> group
153
211
 * $h   -> hostname 
 
212
 * $i   -> client ip/appletalk address without port
154
213
 * $s   -> server name (hostname if it doesn't exist)
155
214
 * $u   -> username (guest is usually nobody)
156
 
 * $v   -> volume name (ADEID_NAME or basename)
 
215
 * $v   -> volume name or basename if null
157
216
 * $z   -> zone (may not exist)
158
217
 * $$   -> $
 
218
 *
 
219
 *
159
220
 */
160
221
#define is_var(a, b) (strncmp((a), (b), 2) == 0)
161
 
static void volxlate(AFPObj *obj, char *dest, int destlen,
162
 
                     char *src, struct passwd *pwd, char *path)
 
222
 
 
223
static char *volxlate(AFPObj *obj, char *dest, size_t destlen,
 
224
                     char *src, struct passwd *pwd, char *path, char *volname)
163
225
{
164
226
    char *p, *q;
165
227
    int len;
166
 
 
167
 
    strncpy(dest, src, destlen);
 
228
    char *ret;
 
229
    
 
230
    if (!src) {
 
231
        return NULL;
 
232
    }
 
233
    if (!dest) {
 
234
        dest = calloc(destlen +1, 1);
 
235
    }
 
236
    ret = dest;
 
237
    if (!ret) {
 
238
        return NULL;
 
239
    }
 
240
    strlcpy(dest, src, destlen +1);
168
241
    if ((p = strchr(src, '$')) == NULL) /* nothing to do */
169
 
        return;
 
242
        return ret;
170
243
 
171
244
    /* first part of the path. just forward to the next variable. */
172
245
    len = MIN(p - src, destlen);
178
251
    while (p && destlen > 0) {
179
252
        /* now figure out what the variable is */
180
253
        q = NULL;
181
 
        if (is_var(p, "$c")) {
 
254
        if (is_var(p, "$b")) {
 
255
            if (path) {
 
256
                if ((q = strrchr(path, '/')) == NULL)
 
257
                    q = path;
 
258
                else if (*(q + 1) != '\0')
 
259
                    q++;
 
260
            }
 
261
        } else if (is_var(p, "$c")) {
182
262
            if (obj->proto == AFPPROTO_ASP) {
183
263
                ASP asp = obj->handle;
184
264
 
195
275
                dest += len;
196
276
                destlen -= len;
197
277
            }
 
278
        } else if (is_var(p, "$d")) {
 
279
             q = path;
198
280
        } else if (is_var(p, "$f")) {
199
281
            if ((q = strchr(pwd->pw_gecos, ',')))
200
282
                *q = '\0';
205
287
                q = grp->gr_name;
206
288
        } else if (is_var(p, "$h")) {
207
289
            q = obj->options.hostname;
 
290
        } else if (is_var(p, "$i")) {
 
291
            if (obj->proto == AFPPROTO_ASP) {
 
292
                ASP asp = obj->handle;
 
293
 
 
294
                len = sprintf(dest, "%u", ntohs(asp->asp_sat.sat_addr.s_net));
 
295
                dest += len;
 
296
                destlen -= len;
 
297
 
 
298
            } else if (obj->proto == AFPPROTO_DSI) {
 
299
                DSI *dsi = obj->handle;
 
300
 
 
301
                q = inet_ntoa(dsi->client.sin_addr);
 
302
            }
208
303
        } else if (is_var(p, "$s")) {
209
304
            if (obj->Obj)
210
305
                q = obj->Obj;
215
310
        } else if (is_var(p, "$u")) {
216
311
            q = obj->username;
217
312
        } else if (is_var(p, "$v")) {
218
 
            if (path) {
219
 
                struct adouble ad;
220
 
 
221
 
                memset(&ad, 0, sizeof(ad));
222
 
                if (ad_open(path, ADFLAGS_HF, O_RDONLY, 0, &ad) < 0)
223
 
                    goto no_volname;
224
 
 
225
 
                if ((len = MIN(ad_getentrylen(&ad, ADEID_NAME), destlen)) > 0) {
226
 
                    memcpy(dest, ad_entry(&ad, ADEID_NAME), len);
227
 
                    ad_close(&ad, ADFLAGS_HF);
228
 
                    dest += len;
229
 
                    destlen -= len;
230
 
                } else {
231
 
                    ad_close(&ad, ADFLAGS_HF);
232
 
no_volname: /* simple basename */
233
 
                    if ((q = strrchr(path, '/')) == NULL)
234
 
                        q = path;
235
 
                    else if (*(q + 1) != '\0')
236
 
                        q++;
237
 
                }
 
313
            if (volname) {
 
314
                q = volname;
 
315
            }
 
316
            else if (path) {
 
317
                if ((q = strrchr(path, '/')) == NULL)
 
318
                    q = path;
 
319
                else if (*(q + 1) != '\0')
 
320
                    q++;
238
321
            }
239
322
        } else if (is_var(p, "$z")) {
240
323
            q = obj->Zone;
262
345
            destlen -= len;
263
346
        }
264
347
    }
 
348
    return ret;
265
349
}
266
350
 
267
351
/* to make sure that val is valid, make sure to select an opt that
268
352
   includes val */
269
 
#define optionok(buf,opt,val) (strstr((buf),(opt)) && ((val)[1] != '\0'))
270
 
 
271
 
static __inline__ char *get_codepage_path(const char *path, const char *name)
272
 
{
273
 
    char *page;
274
 
    int len;
275
 
 
276
 
    if (path) {
277
 
        page = (char *) malloc((len = strlen(path)) + strlen(name) + 2);
278
 
        if (page) {
279
 
            strcpy(page, path);
280
 
            if (path[len - 1] != '/') /* add a / */
281
 
                strcat(page, "/");
282
 
            strcat(page, name);
283
 
        }
284
 
    } else {
285
 
        page = strdup(name);
286
 
    }
287
 
 
288
 
    /* debug: show which codepage directory we are using */
289
 
    LOG(log_debug, logtype_afpd, "using codepage directory: %s", page);
290
 
 
291
 
    return page;
292
 
}
293
 
 
294
 
/* handle all the options. tmp can't be NULL. */
295
 
static void volset(struct vol_option *options, char *volname, int vlen,
296
 
                   const char *nlspath, const char *tmp, AFPObj *obj,
297
 
                   struct passwd *pwd)
 
353
static int optionok(const char *buf, const char *opt, const char *val) 
 
354
{
 
355
    if (!strstr(buf,opt))
 
356
        return 0;
 
357
    if (!val[1])
 
358
        return 0;
 
359
    return 1;    
 
360
}
 
361
 
 
362
 
 
363
/* -------------------- */
 
364
static void setoption(struct vol_option *options, struct vol_option *save, int opt, const char *val)
 
365
{
 
366
    if (options[opt].c_value && (!save || options[opt].c_value != save[opt].c_value))
 
367
        free(options[opt].c_value);
 
368
    options[opt].c_value = strdup(val + 1);
 
369
}
 
370
 
 
371
/* ------------------------------------------
 
372
   handle all the options. tmp can't be NULL. */
 
373
static void volset(struct vol_option *options, struct vol_option *save, 
 
374
                   char *volname, int vlen,
 
375
                   const char *tmp)
298
376
{
299
377
    char *val;
300
378
 
301
 
    LOG(log_debug, logtype_afpd, "Parsing volset %s", tmp);
302
 
 
303
379
    val = strchr(tmp, ':');
304
380
    if (!val) {
305
381
        /* we'll assume it's a volume name. */
306
382
        strncpy(volname, tmp, vlen);
307
 
 
308
 
    } else if (optionok(tmp, "allow:", val)) {
309
 
        if (options[VOLOPT_ALLOW].c_value)
310
 
            free(options[VOLOPT_ALLOW].c_value);
311
 
        options[VOLOPT_ALLOW].c_value = strdup(val + 1);
 
383
        volname[vlen] = 0;
 
384
        return;
 
385
    }
 
386
#if 0
 
387
    LOG(log_debug, logtype_afpd, "Parsing volset %s", val);
 
388
#endif
 
389
    if (optionok(tmp, "allow:", val)) {
 
390
        setoption(options, save, VOLOPT_ALLOW, val);
312
391
 
313
392
    } else if (optionok(tmp, "deny:", val)) {
314
 
        if (options[VOLOPT_DENY].c_value)
315
 
            free(options[VOLOPT_DENY].c_value);
316
 
        options[VOLOPT_DENY].c_value = strdup(val + 1);
 
393
        setoption(options, save, VOLOPT_DENY, val);
317
394
 
318
395
    } else if (optionok(tmp, "rwlist:", val)) {
319
 
        if (options[VOLOPT_RWLIST].c_value)
320
 
            free(options[VOLOPT_RWLIST].c_value);
321
 
        options[VOLOPT_RWLIST].c_value = strdup(val + 1);
 
396
        setoption(options, save, VOLOPT_RWLIST, val);
322
397
 
323
398
    } else if (optionok(tmp, "rolist:", val)) {
324
 
        if (options[VOLOPT_ROLIST].c_value)
325
 
            free(options[VOLOPT_ROLIST].c_value);
326
 
        options[VOLOPT_ROLIST].c_value = strdup(val + 1);
 
399
        setoption(options, save, VOLOPT_ROLIST, val);
327
400
 
328
401
    } else if (optionok(tmp, "codepage:", val)) {
329
 
        if (options[VOLOPT_CODEPAGE].c_value)
330
 
            free(options[VOLOPT_CODEPAGE].c_value);
331
 
        options[VOLOPT_CODEPAGE].c_value = get_codepage_path(nlspath, val + 1);
332
 
 
 
402
        LOG (log_error, logtype_afpd, "The old codepage system has been removed. Please make sure to read the documentation !!!!");
 
403
        /* Make sure we don't screw anything */
 
404
        exit (EXITERR_CONF);
 
405
    } else if (optionok(tmp, "volcharset:", val)) {
 
406
        setoption(options, save, VOLOPT_ENCODING, val);
 
407
    } else if (optionok(tmp, "maccharset:", val)) {
 
408
        setoption(options, save, VOLOPT_MACCHARSET, val);
333
409
    } else if (optionok(tmp, "veto:", val)) {
334
 
        if (options[VOLOPT_VETO].c_value)
335
 
            free(options[VOLOPT_VETO].c_value);
336
 
        options[VOLOPT_VETO].c_value = strdup(val + 1);
337
 
 
 
410
        setoption(options, save, VOLOPT_VETO, val);
 
411
    } else if (optionok(tmp, "cnidscheme:", val)) {
 
412
        setoption(options, save, VOLOPT_CNIDSCHEME, val);
338
413
    } else if (optionok(tmp, "casefold:", val)) {
339
414
        if (strcasecmp(val + 1, "tolower") == 0)
340
415
            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UMLOWER;
344
419
            options[VOLOPT_CASEFOLD].i_value = AFPVOL_UUPPERMLOWER;
345
420
        else if (strcasecmp(val + 1, "xlateupper") == 0)
346
421
            options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER;
347
 
 
 
422
    } else if (optionok(tmp, "adouble:", val)) {
 
423
        if (strcasecmp(val + 1, "v1") == 0)
 
424
            options[VOLOPT_ADOUBLE].i_value = AD_VERSION1;
 
425
#if AD_VERSION == AD_VERSION2            
 
426
        else if (strcasecmp(val + 1, "v2") == 0)
 
427
            options[VOLOPT_ADOUBLE].i_value = AD_VERSION2;
 
428
        else if (strcasecmp(val + 1, "osx") == 0)
 
429
            options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX;
 
430
#endif
348
431
    } else if (optionok(tmp, "options:", val)) {
349
432
        char *p;
350
433
 
355
438
            if (strcasecmp(p, "prodos") == 0)
356
439
                options[VOLOPT_FLAGS].i_value |= AFPVOL_A2VOL;
357
440
            else if (strcasecmp(p, "mswindows") == 0) {
358
 
                options[VOLOPT_FLAGS].i_value |= (AFPVOL_MSWINDOWS | AFPVOL_USEDOTS);
359
 
                if (!options[VOLOPT_CODEPAGE].c_value)
360
 
                    options[VOLOPT_CODEPAGE].c_value =
361
 
                        get_codepage_path(nlspath, MSWINDOWS_CODEPAGE);
362
 
 
 
441
                options[VOLOPT_FLAGS].i_value |= AFPVOL_MSWINDOWS | AFPVOL_USEDOTS;
363
442
            } else if (strcasecmp(p, "crlf") == 0)
364
443
                options[VOLOPT_FLAGS].i_value |= AFPVOL_CRLF;
365
444
            else if (strcasecmp(p, "noadouble") == 0)
379
458
                options[VOLOPT_FLAGS].i_value |= AFPVOL_DROPBOX;
380
459
            else if (strcasecmp(p, "nofileid") == 0)
381
460
                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOFILEID;
 
461
            else if (strcasecmp(p, "nostat") == 0)
 
462
                options[VOLOPT_FLAGS].i_value |= AFPVOL_NOSTAT;
 
463
            else if (strcasecmp(p, "preexec_close") == 0)
 
464
                options[VOLOPT_PREEXEC].i_value = 1;
 
465
            else if (strcasecmp(p, "root_preexec_close") == 0)
 
466
                options[VOLOPT_ROOTPREEXEC].i_value = 1;
 
467
            else if (strcasecmp(p, "upriv") == 0)
 
468
                options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV;
 
469
            else if (strcasecmp(p, "nodev") == 0)
 
470
                options[VOLOPT_FLAGS].i_value |= AFPVOL_NODEV;
 
471
            else if (strcasecmp(p, "cachecnid") == 0)
 
472
                options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE;
382
473
 
383
474
            p = strtok(NULL, ",");
384
475
        }
385
476
 
386
 
#ifdef CNID_DB
387
477
    } else if (optionok(tmp, "dbpath:", val)) {
388
 
        char t[MAXPATHLEN + 1];
389
 
        if (options[VOLOPT_DBPATH].c_value)
390
 
            free(options[VOLOPT_DBPATH].c_value);
 
478
        setoption(options, save, VOLOPT_DBPATH, val);
391
479
 
392
 
        volxlate(obj, t, MAXPATHLEN, val, pwd, NULL);
393
 
        options[VOLOPT_DBPATH].c_value = strdup(t + 1);
394
 
#endif /* CNID_DB */
395
480
    } else if (optionok(tmp, "umask:", val)) {
396
481
        options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8);
397
482
    } else if (optionok(tmp, "mapchars:",val)) {
398
 
        if (options[VOLOPT_MAPCHARS].c_value)
399
 
            free(options[VOLOPT_MAPCHARS].c_value);
400
 
        options[VOLOPT_MAPCHARS].c_value = strdup(val + 1);
 
483
        setoption(options, save, VOLOPT_MAPCHARS, val);
401
484
 
402
485
    } else if (optionok(tmp, "password:", val)) {
403
 
        if (options[VOLOPT_PASSWORD].c_value)
404
 
            free(options[VOLOPT_PASSWORD].c_value);
405
 
        options[VOLOPT_PASSWORD].c_value = strdup(val + 1);
 
486
        setoption(options, save, VOLOPT_PASSWORD, val);
406
487
 
407
488
#ifdef FORCE_UIDGID
408
489
 
409
490
        /* this code allows forced uid/gid per volume settings */
410
491
    } else if (optionok(tmp, "forceuid:", val)) {
411
 
        if (options[VOLOPT_FORCEUID].c_value)
412
 
            free(options[VOLOPT_FORCEUID].c_value);
413
 
        options[VOLOPT_FORCEUID].c_value = strdup(val + 1);
 
492
        setoption(options, save, VOLOPT_FORCEUID, val);
414
493
    } else if (optionok(tmp, "forcegid:", val)) {
415
 
        if (options[VOLOPT_FORCEGID].c_value)
416
 
            free(options[VOLOPT_FORCEGID].c_value);
417
 
        options[VOLOPT_FORCEGID].c_value = strdup(val + 1);
 
494
        setoption(options, save, VOLOPT_FORCEGID, val);
418
495
 
419
496
#endif /* FORCE_UIDGID */
 
497
    } else if (optionok(tmp, "root_preexec:", val)) {
 
498
        setoption(options, save, VOLOPT_ROOTPREEXEC, val);
 
499
 
 
500
    } else if (optionok(tmp, "preexec:", val)) {
 
501
        setoption(options, save, VOLOPT_PREEXEC, val);
 
502
 
 
503
    } else if (optionok(tmp, "root_postexec:", val)) {
 
504
        setoption(options, save, VOLOPT_ROOTPOSTEXEC, val);
 
505
 
 
506
    } else if (optionok(tmp, "postexec:", val)) {
 
507
        setoption(options, save, VOLOPT_POSTEXEC, val);
420
508
 
421
509
    } else {
422
510
        /* ignore unknown options */
423
511
        LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
424
512
 
425
 
    }
426
 
}
427
 
 
428
 
static int creatvol(const char *path, char *name, struct vol_option *options)
 
513
    } 
 
514
}
 
515
 
 
516
/* ----------------- */
 
517
static void showvol(const ucs2_t *name)
 
518
{
 
519
    struct vol  *volume;
 
520
    for ( volume = Volumes; volume; volume = volume->v_next ) {
 
521
        if (volume->v_hide && !strcasecmp_w( volume->v_name, name ) ) {
 
522
            volume->v_hide = 0;
 
523
            return;
 
524
        }
 
525
    }
 
526
}
 
527
 
 
528
/* ----------------- 
 
529
 * FIXME should be define elsewhere
 
530
*/
 
531
static int validupath_adouble(const struct vol *vol, const char *name) 
 
532
{
 
533
    return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent")
 
534
                                           : name[0] != '.';
 
535
}                                           
 
536
 
 
537
/* ----------------- */
 
538
static int validupath_osx(const struct vol *vol, const char *name) 
 
539
{
 
540
    return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2);
 
541
}             
 
542
 
 
543
/* ---------------- */
 
544
static void initvoladouble(struct vol *vol)
 
545
{
 
546
    if (vol->v_adouble == AD_VERSION2_OSX) {
 
547
        vol->validupath  = validupath_osx;
 
548
        vol->ad_path     = ad_path_osx;
 
549
    }
 
550
    else {
 
551
        vol->validupath  = validupath_adouble;
 
552
        vol->ad_path     = ad_path;
 
553
    }
 
554
}
 
555
 
 
556
/* ------------------------------- */
 
557
static int creatvol(AFPObj *obj, struct passwd *pwd, 
 
558
                    char *path, char *name, 
 
559
                    struct vol_option *options, 
 
560
                    const int user /* user defined volume */
 
561
                    )
429
562
{
430
563
    struct vol  *volume;
431
564
    int         vlen;
 
565
    int         hide = 0;
 
566
    ucs2_t      tmpname[512];
432
567
 
433
568
    if ( name == NULL || *name == '\0' ) {
434
569
        if ((name = strrchr( path, '/' )) == NULL) {
440
575
            return -1;
441
576
    }
442
577
 
443
 
    for ( volume = volumes; volume; volume = volume->v_next ) {
444
 
        if ( strcasecmp( volume->v_name, name ) == 0 ) {
445
 
            return -1;  /* Won't be able to access it, anyway... */
446
 
        }
447
 
    }
448
 
 
449
578
    vlen = strlen( name );
450
579
    if ( vlen > AFPVOL_NAMELEN ) {
451
580
        vlen = AFPVOL_NAMELEN;
452
581
        name[AFPVOL_NAMELEN] = '\0';
453
582
    }
454
583
 
455
 
    if (( volume =
456
 
                (struct vol *)calloc(1, sizeof( struct vol ))) == NULL ) {
 
584
    /* convert name to UCS2 first */
 
585
    if ( 0 >= ( vlen = convert_string(obj->options.unixcharset, CH_UCS2, name, vlen, tmpname, 512)) )
 
586
        return -1;
 
587
 
 
588
    for ( volume = Volumes; volume; volume = volume->v_next ) {
 
589
        if ( strcasecmp_w( volume->v_name, tmpname ) == 0 ) {
 
590
           if (volume->v_deleted) {
 
591
               hide = 1;
 
592
           }
 
593
           else {
 
594
               return -1;       /* Won't be able to access it, anyway... */
 
595
           }
 
596
        }
 
597
    }
 
598
 
 
599
 
 
600
    if (!( volume = (struct vol *)calloc(1, sizeof( struct vol ))) ) {
457
601
        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
458
602
        return -1;
459
603
    }
460
 
    if (( volume->v_name =
461
 
                (char *)malloc( vlen + 1 )) == NULL ) {
 
604
    if ( NULL == ( volume->v_name = strdup_w(tmpname))) {
462
605
        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
463
606
        free(volume);
464
607
        return -1;
465
608
    }
466
 
    if (( volume->v_path =
467
 
                (char *)malloc( strlen( path ) + 1 )) == NULL ) {
 
609
    if (!( volume->v_path = (char *)malloc( strlen( path ) + 1 )) ) {
468
610
        LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
469
611
        free(volume->v_name);
470
612
        free(volume);
471
613
        return -1;
472
614
    }
473
 
 
474
 
    strcpy( volume->v_name, name);
 
615
    volume->v_hide = hide;
475
616
    strcpy( volume->v_path, path );
476
617
 
477
618
#ifdef __svr4__
478
619
    volume->v_qfd = -1;
479
620
#endif /* __svr4__ */
480
 
    volume->v_vid = lastvid++;
481
 
    volume->v_lastdid = 17;
 
621
    /* os X start at 1 and use network order ie. 1 2 3 */
 
622
    volume->v_vid = ++lastvid;
 
623
    volume->v_vid = htons(volume->v_vid);
482
624
 
483
625
    /* handle options */
484
626
    if (options) {
488
630
        /* shift in some flags */
489
631
        volume->v_flags = options[VOLOPT_FLAGS].i_value;
490
632
 
491
 
        /* read in the code pages */
492
 
        if (options[VOLOPT_CODEPAGE].c_value)
493
 
            codepage_read(volume, options[VOLOPT_CODEPAGE].c_value);
494
 
 
 
633
        volume->v_ad_options = 0;
 
634
        if ((volume->v_flags & AFPVOL_NODEV))
 
635
            volume->v_ad_options |= ADVOL_NODEV;
 
636
        if ((volume->v_flags & AFPVOL_CACHE))
 
637
            volume->v_ad_options |= ADVOL_CACHE;
 
638
        
495
639
        if (options[VOLOPT_PASSWORD].c_value)
496
640
            volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value);
497
641
 
498
642
        if (options[VOLOPT_VETO].c_value)
499
643
            volume->v_veto = strdup(options[VOLOPT_VETO].c_value);
500
644
 
501
 
#ifdef CNID_DB
 
645
        if (options[VOLOPT_ENCODING].c_value)
 
646
            volume->v_volcodepage = strdup(options[VOLOPT_ENCODING].c_value);
 
647
 
 
648
        if (options[VOLOPT_MACCHARSET].c_value)
 
649
            volume->v_maccodepage = strdup(options[VOLOPT_MACCHARSET].c_value);
 
650
 
502
651
        if (options[VOLOPT_DBPATH].c_value)
503
 
            volume->v_dbpath = strdup(options[VOLOPT_DBPATH].c_value);
504
 
#endif /* CNID_DB */
 
652
            volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_DBPATH].c_value, pwd, path, name);
 
653
 
 
654
       if (options[VOLOPT_CNIDSCHEME].c_value)
 
655
           volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value);
505
656
 
506
657
        if (options[VOLOPT_UMASK].i_value)
507
658
            volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
508
659
 
 
660
        if (options[VOLOPT_ADOUBLE].i_value)
 
661
            volume->v_adouble = options[VOLOPT_ADOUBLE].i_value;
 
662
        else 
 
663
            volume->v_adouble = AD_VERSION;
509
664
#ifdef FORCE_UIDGID
510
 
 
511
665
        if (options[VOLOPT_FORCEUID].c_value) {
512
666
            volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
513
667
        } else {
519
673
        } else {
520
674
            volume->v_forcegid = NULL; /* set as null so as to return 0 later on */
521
675
        }
522
 
 
523
 
#endif /* FORCE_UIDGID */
524
 
 
 
676
#endif
 
677
        if (!user) {
 
678
            if (options[VOLOPT_PREEXEC].c_value)
 
679
                volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path, name);
 
680
            volume->v_preexec_close = options[VOLOPT_PREEXEC].i_value;
 
681
 
 
682
            if (options[VOLOPT_POSTEXEC].c_value)
 
683
                volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path, name);
 
684
 
 
685
            if (options[VOLOPT_ROOTPREEXEC].c_value)
 
686
                volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path,  name);
 
687
            volume->v_root_preexec_close = options[VOLOPT_ROOTPREEXEC].i_value;
 
688
 
 
689
            if (options[VOLOPT_ROOTPOSTEXEC].c_value)
 
690
                volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path,  name);
 
691
        }
525
692
    }
526
693
 
527
 
    volume->v_next = volumes;
528
 
    volumes = volume;
 
694
    initvoladouble(volume);
 
695
    volume->v_next = Volumes;
 
696
    Volumes = volume;
529
697
    return 0;
530
698
}
531
699
 
 
700
/* ---------------- */
532
701
static char *myfgets( buf, size, fp )
533
702
char    *buf;
534
703
int             size;
567
736
 *      0: list exists, but name isn't in it
568
737
 *      1: in list
569
738
 */
 
739
 
 
740
#ifndef NO_REAL_USER_NAME
 
741
/* authentication is case insensitive 
 
742
 * FIXME should we do the same with group name?
 
743
*/
 
744
#define access_strcmp strcasecmp
 
745
 
 
746
#else
 
747
#define access_strcmp strcmp
 
748
 
 
749
#endif
 
750
 
570
751
static int accessvol(args, name)
571
752
const char *args;
572
753
const char *name;
577
758
    if (!args)
578
759
        return -1;
579
760
 
580
 
    strncpy(buf, args, sizeof(buf));
 
761
    strlcpy(buf, args, sizeof(buf));
581
762
    if ((p = strtok(buf, ",")) == NULL) /* nothing, return okay */
582
763
        return -1;
583
764
 
585
766
        if (*p == '@') { /* it's a group */
586
767
            if ((gr = getgrnam(p + 1)) && gmem(gr->gr_gid))
587
768
                return 1;
588
 
        } else if (strcmp(p, name) == 0) /* it's a user name */
 
769
        } else if (access_strcmp(p, name) == 0) /* it's a user name */
589
770
            return 1;
590
771
        p = strtok(NULL, ",");
591
772
    }
600
781
    struct extmap       *em;
601
782
    int                 cnt;
602
783
 
603
 
    if (extmap == NULL) {
604
 
        if (( extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
 
784
    if (Extmap == NULL) {
 
785
        if (( Extmap = calloc(1, sizeof( struct extmap ))) == NULL ) {
605
786
            LOG(log_error, logtype_afpd, "setextmap: calloc: %s", strerror(errno) );
606
787
            return;
607
788
        }
608
789
    }
609
790
    ext++;
610
 
    for ( em = extmap, cnt = 0; em->em_ext; em++, cnt++) {
 
791
    for ( em = Extmap, cnt = 0; em->em_ext; em++, cnt++) {
611
792
        if ( (strdiacasecmp( em->em_ext, ext )) == 0 ) {
612
793
            break;
613
794
        }
614
795
    }
615
796
 
616
797
    if ( em->em_ext == NULL ) {
617
 
        if (!(extmap  = realloc( extmap, sizeof( struct extmap ) * (cnt +2))) ) {
 
798
        if (!(Extmap  = realloc( Extmap, sizeof( struct extmap ) * (cnt +2))) ) {
618
799
            LOG(log_error, logtype_afpd, "setextmap: realloc: %s", strerror(errno) );
619
800
            return;
620
801
        }
621
 
        (extmap +cnt +1)->em_ext = NULL;
622
 
        em = extmap +cnt;
 
802
        (Extmap +cnt +1)->em_ext = NULL;
 
803
        em = Extmap +cnt;
623
804
    } else if ( !user ) {
624
805
        return;
625
806
    }
655
836
{
656
837
    struct extmap       *em;
657
838
 
658
 
    extmap_cnt = 0;
659
 
    if ((em = extmap) == NULL) {
 
839
    Extmap_cnt = 0;
 
840
    if ((em = Extmap) == NULL) {
660
841
        return;
661
842
    }
662
843
    while (em->em_ext) {
663
844
        em++;
664
 
        extmap_cnt++;
665
 
    }
666
 
    if (extmap_cnt) {
667
 
        qsort(extmap, extmap_cnt, sizeof(struct extmap), extmap_cmp);
668
 
        defextmap = extmap;
669
 
    }
670
 
}
671
 
 
672
 
 
673
 
/*
 
845
        Extmap_cnt++;
 
846
    }
 
847
    if (Extmap_cnt) {
 
848
        qsort(Extmap, Extmap_cnt, sizeof(struct extmap), extmap_cmp);
 
849
        if (*Extmap->em_ext == 0) {
 
850
            /* the first line is really "." the default entry, 
 
851
             * we remove the leading '.' in setextmap
 
852
            */
 
853
            Defextmap = Extmap;
 
854
        }
 
855
    }
 
856
}
 
857
 
 
858
/* ----------------------
 
859
*/
 
860
static void free_extmap( void)
 
861
{
 
862
    struct extmap       *em;
 
863
 
 
864
    if (Extmap) {
 
865
        for ( em = Extmap; em->em_ext; em++) {
 
866
             free (em->em_ext);
 
867
        }
 
868
        free(Extmap);
 
869
        Extmap = NULL;
 
870
        Defextmap = Extmap;
 
871
        Extmap_cnt = 0;
 
872
    }
 
873
}
 
874
 
 
875
/* ----------------------
 
876
*/
 
877
static int volfile_changed(struct afp_volume_name *p) 
 
878
{
 
879
    struct stat      st;
 
880
    char *name;
 
881
    
 
882
    if (p->full_name) 
 
883
        name = p->full_name;
 
884
    else
 
885
        name = p->name;
 
886
        
 
887
    if (!stat( name, &st) && st.st_mtime > p->mtime) {
 
888
        p->mtime = st.st_mtime;
 
889
        return 1;
 
890
    }
 
891
    return 0;
 
892
}
 
893
 
 
894
/* ----------------------
674
895
 * Read a volume configuration file and add the volumes contained within to
675
896
 * the global volume list.  If p2 is non-NULL, the file that is opened is
676
897
 * p1/p2
677
 
 *
 
898
 * 
678
899
 * Lines that begin with # and blank lines are ignored.
679
900
 * Volume lines are of the form:
680
901
 *              <unix path> [<volume name>] [allow:<user>,<@group>,...] \
683
904
 */
684
905
static int readvolfile(obj, p1, p2, user, pwent)
685
906
AFPObj      *obj;
686
 
char    *p1, *p2;
 
907
struct afp_volume_name  *p1;
 
908
char        *p2;
687
909
int             user;
688
910
struct passwd *pwent;
689
911
{
695
917
    struct passwd       *pw;
696
918
    struct vol_option   options[VOLOPT_NUM], save_options[VOLOPT_NUM];
697
919
    int                 i;
 
920
    struct stat         st;
 
921
    int                 fd;
698
922
 
699
 
    if (!p1)
 
923
    if (!p1->name)
700
924
        return -1;
701
 
 
702
 
    strcpy( path, p1 );
 
925
    p1->mtime = 0;
 
926
    strcpy( path, p1->name );
703
927
    if ( p2 != NULL ) {
704
928
        strcat( path, "/" );
705
929
        strcat( path, p2 );
 
930
        if (p1->full_name) {
 
931
            free(p1->full_name);
 
932
        }
 
933
        p1->full_name = strdup(path);
706
934
    }
707
935
 
708
936
    if (NULL == ( fp = fopen( path, "r" )) ) {
709
937
        return( -1 );
710
938
    }
 
939
    fd = fileno(fp);
 
940
    if (fd != -1 && !fstat( fd, &st) ) {
 
941
        p1->mtime = st.st_mtime;
 
942
    }
711
943
 
712
944
    memset(save_options, 0, sizeof(save_options));
713
945
    while ( myfgets( buf, sizeof( buf ), fp ) != NULL ) {
726
958
                    if (parseline( sizeof( path ) - VOLOPT_DEFAULT_LEN - 1,
727
959
                                   path + VOLOPT_DEFAULT_LEN) < 0)
728
960
                        break;
729
 
                    volset(save_options, tmp, sizeof(tmp) - 1,
730
 
                           obj->options.nlspath, path + VOLOPT_DEFAULT_LEN,
731
 
                           obj, pwent);
 
961
                    volset(save_options, NULL, tmp, sizeof(tmp) - 1,
 
962
                           path + VOLOPT_DEFAULT_LEN);
732
963
                }
733
964
            }
734
965
            break;
762
993
                strcpy(tmp, path);
763
994
            if (!pwent)
764
995
                pwent = getpwnam(obj->username);
765
 
            volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL);
 
996
            volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL);
766
997
 
767
998
            /* this is sort of braindead. basically, i want to be
768
999
             * able to specify things in any order, but i don't want to 
769
1000
             * re-write everything. 
770
1001
             *
771
 
             * currently we have 11 options: 
 
1002
             * currently we have options: 
772
1003
             *   volname
773
1004
             *   codepage:x
774
1005
             *   casefold:x
776
1007
             *   deny:x,y,@z
777
1008
             *   rwlist:x,y,@z
778
1009
             *   rolist:x,y,@z
779
 
             *   options:prodos,crlf,noadouble,ro
 
1010
             *   options:prodos,crlf,noadouble,ro...
780
1011
             *   dbpath:x
781
1012
             *   password:x
 
1013
             *   preexec:x
 
1014
             *
782
1015
             *   namemask:x,y,!z  (not implemented yet)
783
1016
             */
784
1017
            memcpy(options, save_options, sizeof(options));
785
1018
            *volname = '\0';
786
1019
 
787
 
            /* read in up to 11 possible options */
 
1020
            /* read in up to VOLOP_NUM possible options */
788
1021
            for (i = 0; i < VOLOPT_NUM; i++) {
789
1022
                if (parseline( sizeof( tmp ) - 1, tmp ) < 0)
790
1023
                    break;
791
1024
 
792
 
                volset(options, volname, sizeof(volname) - 1,
793
 
                       obj->options.nlspath, tmp, obj, pwent);
 
1025
                volset(options, save_options, volname, sizeof(volname) - 1, tmp);
794
1026
            }
795
1027
 
796
1028
            /* check allow/deny lists:
810
1042
                                    obj->username)))
811
1043
                    options[VOLOPT_FLAGS].i_value |= AFPVOL_RO;
812
1044
 
813
 
                /* do variable substitution */
814
 
                volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path);
815
 
                creatvol(path, tmp, options);
 
1045
                /* do variable substitution for volname */
 
1046
                volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL);
 
1047
                creatvol(obj, pwent, path, tmp, options, p2 != NULL);
816
1048
            }
817
1049
            volfree(options, save_options);
818
1050
            break;
832
1064
    if ( fclose( fp ) != 0 ) {
833
1065
        LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
834
1066
    }
 
1067
    p1->loaded = 1;
835
1068
    return( 0 );
836
1069
}
837
1070
 
838
 
 
839
 
static void load_volumes(AFPObj *obj)
840
 
{
841
 
    struct passwd       *pwent = getpwnam(obj->username);
842
 
 
843
 
    if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
844
 
        readvolfile(obj, obj->options.systemvol, NULL, 0, pwent);
845
 
    }
846
 
 
847
 
    if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
848
 
        readvolfile(obj, obj->options.defaultvol, NULL, 1, pwent);
849
 
    } else if (pwent) {
850
 
        /*
851
 
        * Read user's AppleVolumes or .AppleVolumes file
852
 
        * If neither are readable, read the default volumes file. if
853
 
        * that doesn't work, create a user share.
854
 
        */
855
 
        if ( readvolfile(obj, pwent->pw_dir, "AppleVolumes", 1, pwent) < 0 &&
856
 
                readvolfile(obj, pwent->pw_dir, ".AppleVolumes", 1, pwent) < 0 &&
857
 
                readvolfile(obj, pwent->pw_dir, "applevolumes", 1, pwent) < 0 &&
858
 
                readvolfile(obj, pwent->pw_dir, ".applevolumes", 1, pwent) < 0 &&
859
 
                obj->options.defaultvol != NULL ) {
860
 
            if (readvolfile(obj, obj->options.defaultvol, NULL, 1, pwent) < 0)
861
 
                creatvol(pwent->pw_dir, NULL, NULL);
862
 
        }
863
 
    }
864
 
    if ( obj->options.flags & OPTION_USERVOLFIRST ) {
865
 
        readvolfile(obj, obj->options.systemvol, NULL, 0, pwent );
 
1071
/* ------------------------------- */
 
1072
static void volume_free(struct vol *vol)
 
1073
{
 
1074
    free(vol->v_name);
 
1075
    vol->v_name = NULL;
 
1076
    free(vol->v_path);
 
1077
    free(vol->v_password);
 
1078
    free(vol->v_veto);
 
1079
    free(vol->v_volcodepage);
 
1080
    free(vol->v_maccodepage);
 
1081
    free(vol->v_cnidscheme);
 
1082
    free(vol->v_dbpath);
 
1083
    free(vol->v_gvs);
 
1084
#ifdef FORCE_UIDGID
 
1085
    free(vol->v_forceuid);
 
1086
    free(vol->v_forcegid);
 
1087
#endif /* FORCE_UIDGID */
 
1088
}
 
1089
 
 
1090
/* ------------------------------- */
 
1091
static void free_volumes(void )
 
1092
{
 
1093
    struct vol  *vol;
 
1094
    struct vol  *nvol, *ovol;
 
1095
 
 
1096
    for ( vol = Volumes; vol; vol = vol->v_next ) {
 
1097
        if (( vol->v_flags & AFPVOL_OPEN ) ) {
 
1098
            vol->v_deleted = 1;
 
1099
            continue;
 
1100
        }
 
1101
        volume_free(vol);
 
1102
    }
 
1103
 
 
1104
    for ( vol = Volumes, ovol = NULL; vol; vol = nvol) {
 
1105
        nvol = vol->v_next;
 
1106
 
 
1107
        if (vol->v_name == NULL) {
 
1108
           if (Volumes == vol) {
 
1109
               Volumes = nvol;
 
1110
               ovol = Volumes;
 
1111
           }
 
1112
           else {
 
1113
              ovol->v_next = nvol;
 
1114
           }
 
1115
           free(vol);
 
1116
        }
 
1117
        else {
 
1118
           ovol = vol;
 
1119
        }
 
1120
    }
 
1121
}
 
1122
 
 
1123
/* ------------------------------- */
 
1124
static void volume_unlink(struct vol *volume)
 
1125
{
 
1126
struct vol *vol, *ovol, *nvol;
 
1127
 
 
1128
    if (volume == Volumes) {
 
1129
        Volumes = Volumes->v_next;
 
1130
        return;
 
1131
    }
 
1132
    for ( vol = Volumes->v_next, ovol = Volumes; vol; vol = nvol) {
 
1133
        nvol = vol->v_next;
 
1134
 
 
1135
        if (vol == volume) {
 
1136
            ovol->v_next = nvol;
 
1137
            break;
 
1138
        }
 
1139
        else {
 
1140
           ovol = vol;
 
1141
        }
866
1142
    }
867
1143
}
868
1144
 
875
1151
    u_int32_t   maxsize;
876
1152
#ifndef NO_QUOTA_SUPPORT
877
1153
    VolSpace    qfree, qtotal;
878
 
#endif /* ! NO_QUOTA_SUPPORT */
 
1154
#endif
879
1155
 
880
1156
    spaceflag = AFPVOL_GVSMASK & vol->v_flags;
881
1157
    /* report up to 2GB if afp version is < 2.2 (4GB if not) */
890
1166
            goto getvolspace_done;
891
1167
        }
892
1168
    }
893
 
#endif /* AFS */
 
1169
#endif
894
1170
 
895
1171
    if (( rc = ustatfs_getvolspace( vol, xbfree, xbtotal,
896
1172
                                    bsize)) != AFP_OK ) {
907
1183
            goto getvolspace_done;
908
1184
        }
909
1185
    }
910
 
#endif /* ! NO_QUOTA_SUPPORT */
 
1186
#endif
911
1187
    vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_USTATFS;
912
1188
 
913
1189
getvolspace_done:
916
1192
    return( AFP_OK );
917
1193
}
918
1194
 
 
1195
/* ----------------------- 
 
1196
 * set volume creation date
 
1197
 * avoid duplicate, well at least it tries
 
1198
*/
 
1199
static void vol_setdate(u_int16_t id, struct adouble *adp, time_t date)
 
1200
{
 
1201
    struct vol  *volume;
 
1202
    struct vol  *vol = Volumes;
 
1203
 
 
1204
    for ( volume = Volumes; volume; volume = volume->v_next ) {
 
1205
        if (volume->v_vid == id) {
 
1206
            vol = volume;
 
1207
        }
 
1208
        else if (AD_DATE_FROM_UNIX(date) == volume->v_ctime) {
 
1209
            date = date+1;
 
1210
            volume = Volumes; /* restart */
 
1211
        }
 
1212
    }
 
1213
    vol->v_ctime = AD_DATE_FROM_UNIX(date);
 
1214
    ad_setdate(adp, AD_DATE_CREATE | AD_DATE_UNIX, date);
 
1215
}
 
1216
 
 
1217
/* ----------------------- */
919
1218
static int getvolparams( bitmap, vol, st, buf, buflen )
920
1219
u_int16_t       bitmap;
921
1220
struct vol      *vol;
936
1235
     * For MacOS8.x support we need to create the
937
1236
     * .Parent file here if it doesn't exist. */
938
1237
 
939
 
    memset(&ad, 0, sizeof(ad));
 
1238
    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
940
1239
    if ( ad_open( vol->v_path, vol_noadouble(vol) |
941
1240
                  ADFLAGS_HF|ADFLAGS_DIR, O_RDWR | O_CREAT,
942
1241
                  0666, &ad) < 0 ) {
943
1242
        isad = 0;
 
1243
        vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
944
1244
 
945
 
    } else if (ad_getoflags( &ad, ADFLAGS_HF ) & O_CREAT) {
 
1245
    } else if (ad_get_HF_flags( &ad ) & O_CREAT) {
946
1246
        slash = strrchr( vol->v_path, '/' );
947
1247
        if(slash)
948
1248
            slash++;
949
1249
        else
950
1250
            slash = vol->v_path;
951
 
 
952
 
        ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
953
 
        memcpy(ad_entry( &ad, ADEID_NAME ), slash,
 
1251
        if (ad_getentryoff(&ad, ADEID_NAME)) {
 
1252
            ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
 
1253
            memcpy(ad_entry( &ad, ADEID_NAME ), slash,
954
1254
               ad_getentrylen( &ad, ADEID_NAME ));
955
 
        ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st->st_mtime);
 
1255
        }
 
1256
        vol_setdate(vol->v_vid, &ad, st->st_mtime);
956
1257
        ad_flush(&ad, ADFLAGS_HF);
957
1258
    }
 
1259
    else {
 
1260
        if (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0)
 
1261
            vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
 
1262
        else 
 
1263
            vol->v_ctime = aint;
 
1264
    }
958
1265
 
959
1266
    if (( bitmap & ( (1<<VOLPBIT_BFREE)|(1<<VOLPBIT_BTOTAL) |
960
1267
                     (1<<VOLPBIT_XBFREE)|(1<<VOLPBIT_XBTOTAL) |
978
1285
        switch ( bit ) {
979
1286
        case VOLPBIT_ATTR :
980
1287
            ashort = 0;
981
 
#ifdef CNID_DB
982
 
            if (0 == (vol->v_flags & AFPVOL_NOFILEID)) {
 
1288
            if (0 == (vol->v_flags & AFPVOL_NOFILEID) && vol->v_cdb != NULL &&
 
1289
                           (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
983
1290
                ashort = VOLPBIT_ATTR_FILEID;
984
1291
            }
985
 
#endif /* CNID_DB */
986
1292
            /* check for read-only.
987
1293
             * NOTE: we don't actually set the read-only flag unless
988
1294
             *       it's passed in that way as it's possible to mount
989
1295
             *       a read-write filesystem under a read-only one. */
990
1296
            if ((vol->v_flags & AFPVOL_RO) ||
991
 
                    ((utime(vol->v_path, NULL) < 0) && (errno == EROFS)))
 
1297
                    ((utime(vol->v_path, NULL) < 0) && (errno == EROFS))) {
992
1298
                ashort |= VOLPBIT_ATTR_RO;
993
 
                ashort |= VOLPBIT_ATTR_CATSEARCH;
 
1299
            }
 
1300
            ashort |= VOLPBIT_ATTR_CATSEARCH;
 
1301
            if (afp_version >= 30) {
 
1302
                ashort |= VOLPBIT_ATTR_UTF8;
 
1303
                if (vol->v_flags & AFPVOL_UNIX_PRIV)
 
1304
                    ashort |= VOLPBIT_ATTR_UNIXPRIV;
 
1305
            }
994
1306
            ashort = htons(ashort);
995
1307
            memcpy(data, &ashort, sizeof( ashort ));
996
1308
            data += sizeof( ashort );
1003
1315
            break;
1004
1316
 
1005
1317
        case VOLPBIT_CDATE :
1006
 
            if (!isad || (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0))
1007
 
                aint = AD_DATE_FROM_UNIX(st->st_mtime);
 
1318
            aint = vol->v_ctime;
1008
1319
            memcpy(data, &aint, sizeof( aint ));
1009
1320
            data += sizeof( aint );
1010
1321
            break;
1011
1322
 
1012
1323
        case VOLPBIT_MDATE :
1013
 
            if ( st->st_mtime > vol->v_time ) {
1014
 
                vol->v_time = st->st_mtime;
1015
 
                aint = AD_DATE_FROM_UNIX(st->st_mtime);
1016
 
            } else {
1017
 
                aint = AD_DATE_FROM_UNIX(vol->v_time);
 
1324
            if ( st->st_mtime > vol->v_mtime ) {
 
1325
                vol->v_mtime = st->st_mtime;
1018
1326
            }
 
1327
            aint = AD_DATE_FROM_UNIX(vol->v_mtime);
1019
1328
            memcpy(data, &aint, sizeof( aint ));
1020
1329
            data += sizeof( aint );
1021
1330
            break;
1089
1398
    if ( nameoff ) {
1090
1399
        ashort = htons( data - buf );
1091
1400
        memcpy(nameoff, &ashort, sizeof( ashort ));
1092
 
        aint = strlen( vol->v_name );
 
1401
        aint = ucs2_to_charset( (utf8_encoding()?CH_UTF8_MAC:vol->v_maccharset), vol->v_name, data+1, 255);
 
1402
        if ( aint <= 0 ) {
 
1403
            *buflen = 0;
 
1404
            return AFPERR_MISC;
 
1405
        }
 
1406
                
1093
1407
        *data++ = aint;
1094
 
        memcpy(data, vol->v_name, aint );
1095
1408
        data += aint;
1096
1409
    }
1097
1410
    if ( isad ) {
1101
1414
    return( AFP_OK );
1102
1415
}
1103
1416
 
1104
 
 
1105
 
 
 
1417
/* ------------------------- */
 
1418
static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen)
 
1419
{
 
1420
    struct stat st;
 
1421
    int         buflen, ret;
 
1422
 
 
1423
    if ( stat( vol->v_path, &st ) < 0 ) {
 
1424
        *rbuflen = 0;
 
1425
        return( AFPERR_PARAM );
 
1426
    }
 
1427
    /* save the volume device number */
 
1428
    vol->v_dev = st.st_dev;
 
1429
 
 
1430
    buflen = *rbuflen - sizeof( bitmap );
 
1431
    if (( ret = getvolparams( bitmap, vol, &st,
 
1432
                              rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) {
 
1433
        *rbuflen = 0;
 
1434
        return( ret );
 
1435
    }
 
1436
    *rbuflen = buflen + sizeof( bitmap );
 
1437
    bitmap = htons( bitmap );
 
1438
    memcpy(rbuf, &bitmap, sizeof( bitmap ));
 
1439
    return( AFP_OK );
 
1440
 
 
1441
}
 
1442
 
 
1443
/* ------------------------------- */
 
1444
void load_volumes(AFPObj *obj)
 
1445
{
 
1446
    struct passwd       *pwent;
 
1447
 
 
1448
    if (Volumes) {
 
1449
        int changed = 0;
 
1450
        
 
1451
        /* check files date */
 
1452
        if (obj->options.defaultvol.loaded) {
 
1453
            changed = volfile_changed(&obj->options.defaultvol);
 
1454
        }
 
1455
        if (obj->options.systemvol.loaded) {
 
1456
            changed |= volfile_changed(&obj->options.systemvol);
 
1457
        }
 
1458
        if (obj->options.uservol.loaded) {
 
1459
            changed |= volfile_changed(&obj->options.uservol);
 
1460
        }
 
1461
        if (!changed)
 
1462
            return;
 
1463
        
 
1464
        free_extmap();
 
1465
        free_volumes();
 
1466
    }
 
1467
    
 
1468
    pwent = getpwnam(obj->username);
 
1469
    if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
 
1470
        readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent);
 
1471
    }
 
1472
 
 
1473
    if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
 
1474
        readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent);
 
1475
    } else if (pwent) {
 
1476
        /*
 
1477
        * Read user's AppleVolumes or .AppleVolumes file
 
1478
        * If neither are readable, read the default volumes file. if
 
1479
        * that doesn't work, create a user share.
 
1480
        */
 
1481
        if (obj->options.uservol.name) {
 
1482
            free(obj->options.uservol.name);
 
1483
        }
 
1484
        obj->options.uservol.name = strdup(pwent->pw_dir);
 
1485
        if ( readvolfile(obj, &obj->options.uservol,    "AppleVolumes", 1, pwent) < 0 &&
 
1486
                readvolfile(obj, &obj->options.uservol, ".AppleVolumes", 1, pwent) < 0 &&
 
1487
                readvolfile(obj, &obj->options.uservol, "applevolumes", 1, pwent) < 0 &&
 
1488
                readvolfile(obj, &obj->options.uservol, ".applevolumes", 1, pwent) < 0 &&
 
1489
                obj->options.defaultvol.name != NULL ) {
 
1490
            if (readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent) < 0)
 
1491
                creatvol(obj, pwent, pwent->pw_dir, NULL, NULL, 1);
 
1492
        }
 
1493
    }
 
1494
    if ( obj->options.flags & OPTION_USERVOLFIRST ) {
 
1495
        readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent );
 
1496
    }
 
1497
}
 
1498
 
 
1499
/* ------------------------------- */
1106
1500
int afp_getsrvrparms(obj, ibuf, ibuflen, rbuf, rbuflen )
1107
1501
AFPObj      *obj;
1108
1502
char    *ibuf, *rbuf;
1112
1506
    struct stat         st;
1113
1507
    struct vol          *volume;
1114
1508
    char        *data;
1115
 
    int                 vcnt, len;
1116
 
 
1117
 
 
1118
 
    if (!volumes)
1119
 
        load_volumes(obj);
 
1509
    char                *namebuf;
 
1510
    int                 vcnt;
 
1511
    size_t              len;
 
1512
 
 
1513
    load_volumes(obj);
1120
1514
 
1121
1515
    data = rbuf + 5;
1122
 
    for ( vcnt = 0, volume = volumes; volume; volume = volume->v_next ) {
1123
 
        if ( stat( volume->v_path, &st ) < 0 ) {
1124
 
            LOG(log_info, logtype_afpd, "afp_getsrvrparms: stat %s: %s",
1125
 
                volume->v_path, strerror(errno) );
1126
 
            continue;           /* can't access directory */
1127
 
        }
1128
 
        if (!S_ISDIR(st.st_mode)) {
1129
 
            continue;           /* not a dir */
1130
 
        }
 
1516
    for ( vcnt = 0, volume = Volumes; volume; volume = volume->v_next ) {
 
1517
        if (!(volume->v_flags & AFPVOL_NOSTAT)) {
 
1518
            if ( stat( volume->v_path, &st ) < 0 ) {
 
1519
                LOG(log_info, logtype_afpd, "afp_getsrvrparms(%s): stat: %s",
 
1520
                        volume->v_path, strerror(errno) );
 
1521
                continue;               /* can't access directory */
 
1522
            }
 
1523
            if (!S_ISDIR(st.st_mode)) {
 
1524
                continue;               /* not a dir */
 
1525
            }
 
1526
        }
 
1527
        if (volume->v_hide) {
 
1528
            continue;           /* config file changed but the volume was mounted */
 
1529
        }
 
1530
        len = ucs2_to_charset_allocate((utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset),
 
1531
                                        &namebuf, volume->v_name);
 
1532
        if (len == (size_t)-1)
 
1533
                continue;
1131
1534
 
1132
1535
        /* set password bit if there's a volume password */
1133
1536
        *data = (volume->v_password) ? AFPSRVR_PASSWD : 0;
1138
1541
           completely worked this out, but it's related to booting
1139
1542
           from the server.  Support for that function is a ways
1140
1543
           off.. <shirsch@ibm.net> */
1141
 
        *data++ |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0;
1142
 
        len = strlen( volume->v_name );
 
1544
        *data |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0;
 
1545
        *data++ |= 0; /* UNIX PRIVS BIT ..., OSX doesn't seem to use it, so we don't either */
1143
1546
        *data++ = len;
1144
 
        memcpy(data, volume->v_name, len );
 
1547
        memcpy(data, namebuf, len );
1145
1548
        data += len;
 
1549
        free(namebuf);
1146
1550
        vcnt++;
1147
1551
    }
1148
1552
 
1149
1553
    *rbuflen = data - rbuf;
1150
1554
    data = rbuf;
1151
1555
    if ( gettimeofday( &tv, 0 ) < 0 ) {
1152
 
        LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
 
1556
        LOG(log_error, logtype_afpd, "afp_getsrvrparms(%s): gettimeofday: %s", volume->v_path, strerror(errno) );
1153
1557
        *rbuflen = 0;
1154
1558
        return AFPERR_PARAM;
1155
1559
    }
1160
1564
    return( AFP_OK );
1161
1565
}
1162
1566
 
 
1567
/* ------------------------- 
 
1568
 * we are the user here
 
1569
*/
1163
1570
int afp_openvol(obj, ibuf, ibuflen, rbuf, rbuflen )
1164
1571
AFPObj      *obj;
1165
1572
char    *ibuf, *rbuf;
1167
1574
{
1168
1575
    struct stat st;
1169
1576
    char        *volname;
1170
 
#ifndef CNID_DB
1171
 
    char *p;
1172
 
#endif /* CNID_DB */
 
1577
    char        *p;
1173
1578
    struct vol  *volume;
1174
1579
    struct dir  *dir;
1175
 
    int         len, ret, buflen;
 
1580
    int         len, ret;
 
1581
    size_t      namelen;
1176
1582
    u_int16_t   bitmap;
 
1583
    char        path[ MAXPATHLEN + 1];
 
1584
    char        *vol_uname;
 
1585
    char        *vol_mname;
1177
1586
 
1178
1587
    ibuf += 2;
1179
1588
    memcpy(&bitmap, ibuf, sizeof( bitmap ));
1180
1589
    bitmap = ntohs( bitmap );
1181
1590
    ibuf += sizeof( bitmap );
1182
1591
    if (( bitmap & (1<<VOLPBIT_VID)) == 0 ) {
1183
 
        ret = AFPERR_BITMAP;
1184
 
        goto openvol_err;
 
1592
        *rbuflen = 0;
 
1593
        return AFPERR_BITMAP;
1185
1594
    }
1186
1595
 
1187
1596
    len = (unsigned char)*ibuf++;
1188
1597
    volname = obj->oldtmp;
1189
 
    memcpy(volname, ibuf, len );
1190
 
    *(volname +  len) = '\0';
 
1598
    namelen = convert_string( (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), CH_UCS2,
 
1599
                              ibuf, len, volname, sizeof(obj->oldtmp));
 
1600
    if ( namelen <= 0){
 
1601
        *rbuflen = 0;
 
1602
        return AFPERR_PARAM;
 
1603
    }
 
1604
 
1191
1605
    ibuf += len;
1192
1606
    if ((len + 1) & 1) /* pad to an even boundary */
1193
1607
        ibuf++;
1194
1608
 
1195
 
    if (!volumes)
1196
 
        load_volumes(obj);
 
1609
    load_volumes(obj);
1197
1610
 
1198
 
    for ( volume = volumes; volume; volume = volume->v_next ) {
1199
 
        if ( strcasecmp( volname, volume->v_name ) == 0 ) {
 
1611
    for ( volume = Volumes; volume; volume = volume->v_next ) {
 
1612
        if ( strcasecmp_w( (ucs2_t*) volname, volume->v_name ) == 0 ) {
1200
1613
            break;
1201
1614
        }
1202
1615
    }
1203
1616
 
1204
1617
    if ( volume == NULL ) {
1205
 
        ret = AFPERR_PARAM;
1206
 
        goto openvol_err;
 
1618
        *rbuflen = 0;
 
1619
        return AFPERR_PARAM;
1207
1620
    }
1208
1621
 
1209
1622
    /* check for a volume password */
1210
 
    if (volume->v_password &&
1211
 
            strncmp(ibuf, volume->v_password, VOLPASSLEN)) {
1212
 
        ret = AFPERR_ACCESS;
1213
 
        goto openvol_err;
1214
 
    }
1215
 
 
1216
 
    if (( volume->v_flags & AFPVOL_OPEN  ) == 0 ) {
1217
 
        if ((dir = dirnew(strlen(volume->v_name) + 1)) == NULL) {
1218
 
            LOG(log_error, logtype_afpd, "afp_openvol: malloc: %s", strerror(errno) );
 
1623
    if (volume->v_password && strncmp(ibuf, volume->v_password, VOLPASSLEN)) {
 
1624
        *rbuflen = 0;
 
1625
        return AFPERR_ACCESS;
 
1626
    }
 
1627
 
 
1628
    if (( volume->v_flags & AFPVOL_OPEN  ) ) {
 
1629
        /* the volume is already open */
 
1630
#ifdef FORCE_UIDGID
 
1631
        set_uidgid ( volume );
 
1632
#endif
 
1633
        return stat_vol(bitmap, volume, rbuf, rbuflen);
 
1634
    }
 
1635
 
 
1636
    /* initialize volume variables
 
1637
     * FIXME file size
 
1638
    */
 
1639
    if (afp_version >= 30) {
 
1640
        volume->max_filename = 255;
 
1641
    }
 
1642
    else {
 
1643
        volume->max_filename = MACFILELEN;
 
1644
    }
 
1645
 
 
1646
    volume->v_dir = volume->v_root = NULL;
 
1647
 
 
1648
    volume->v_flags |= AFPVOL_OPEN;
 
1649
    volume->v_cdb = NULL;  
 
1650
 
 
1651
    if (volume->v_root_preexec) {
 
1652
        if ((ret = afprun(1, volume->v_root_preexec, NULL)) && volume->v_root_preexec_close) {
 
1653
            LOG(log_error, logtype_afpd, "afp_openvol(%s): root preexec : %d", volume->v_path, ret );
1219
1654
            ret = AFPERR_MISC;
1220
1655
            goto openvol_err;
1221
 
        }
1222
 
        dir->d_did = DIRDID_ROOT;
1223
 
        dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */
1224
 
        strcpy( dir->d_name, volume->v_name );
1225
 
        volume->v_dir = volume->v_root = dir;
1226
 
        volume->v_flags |= AFPVOL_OPEN;
 
1656
        }
1227
1657
    }
 
1658
 
1228
1659
#ifdef FORCE_UIDGID
1229
1660
    set_uidgid ( volume );
1230
 
#endif /* FORCE_UIDGID */
 
1661
#endif
 
1662
 
 
1663
    if (volume->v_preexec) {
 
1664
        if ((ret = afprun(0, volume->v_preexec, NULL)) && volume->v_preexec_close) {
 
1665
            LOG(log_error, logtype_afpd, "afp_openvol(%s): preexec : %d", volume->v_path, ret );
 
1666
            ret = AFPERR_MISC;
 
1667
            goto openvol_err;
 
1668
        }
 
1669
    }
1231
1670
 
1232
1671
    if ( stat( volume->v_path, &st ) < 0 ) {
1233
1672
        ret = AFPERR_PARAM;
1234
1673
        goto openvol_err;
1235
1674
    }
1236
1675
 
1237
 
    buflen = *rbuflen - sizeof( bitmap );
1238
 
    if (( ret = getvolparams( bitmap, volume, &st,
1239
 
                              rbuf + sizeof(bitmap), &buflen )) != AFP_OK ) {
1240
 
        goto openvol_err;
1241
 
    }
1242
 
    *rbuflen = buflen + sizeof( bitmap );
1243
 
    bitmap = htons( bitmap );
1244
 
    memcpy(rbuf, &bitmap, sizeof( bitmap ));
1245
 
 
1246
1676
    if ( chdir( volume->v_path ) < 0 ) {
1247
1677
        ret = AFPERR_PARAM;
1248
1678
        goto openvol_err;
1249
1679
    }
 
1680
 
 
1681
    len = convert_string_allocate( CH_UCS2, (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset),
 
1682
                                       volume->v_name, namelen, &vol_mname);
 
1683
    if ( !vol_mname || len <= 0) {
 
1684
        ret = AFPERR_MISC;
 
1685
        goto openvol_err;
 
1686
    }
 
1687
    
 
1688
    if ( NULL == getcwd(path, MAXPATHLEN)) {
 
1689
        /* shouldn't be fatal but it will fail later */
 
1690
        LOG(log_error, logtype_afpd, "afp_openvol(%s): volume pathlen too long", volume->v_path);
 
1691
        ret = AFPERR_MISC;
 
1692
        goto openvol_err;
 
1693
    }        
 
1694
    
 
1695
    if ((vol_uname = strrchr(path, '/')) == NULL)
 
1696
         vol_uname = path;
 
1697
    else if (*(vol_uname + 1) != '\0')
 
1698
         vol_uname++;
 
1699
        
 
1700
    if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) {
 
1701
        free(vol_mname);
 
1702
        LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) );
 
1703
        ret = AFPERR_MISC;
 
1704
        goto openvol_err;
 
1705
    }
 
1706
    free(vol_mname);
 
1707
 
 
1708
    dir->d_did = DIRDID_ROOT;
 
1709
    dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */
 
1710
    volume->v_dir = volume->v_root = dir;
 
1711
 
1250
1712
    curdir = volume->v_dir;
1251
 
 
1252
 
#ifdef CNID_DB
 
1713
    if (volume->v_cnidscheme == NULL) {
 
1714
        volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME);
 
1715
        LOG(log_warning, logtype_afpd, "Warning: No CNID scheme for volume %s. Using default.",
 
1716
               volume->v_path);
 
1717
    }
1253
1718
    if (volume->v_dbpath)
1254
 
        volume->v_db = cnid_open (volume->v_dbpath, volume->v_umask);
1255
 
    if (volume->v_db == NULL)
1256
 
        volume->v_db = cnid_open (volume->v_path, volume->v_umask);
1257
 
#endif /* CNID_DB */
1258
 
 
1259
 
#ifndef CNID_DB
1260
 
    /*
1261
 
     * If you mount a volume twice, the second time the trash appears on
1262
 
     * the desk-top.  That's because the Mac remembers the DID for the
1263
 
     * trash (even for volumes in different zones, on different servers).
1264
 
     * Just so this works better, we prime the DID cache with the trash,
1265
 
     * fixing the trash at DID 17.
1266
 
     */
1267
 
    p = Trash;
1268
 
    cname( volume, volume->v_dir, &p );
1269
 
#endif /* CNID_DB */
1270
 
 
1271
 
    return( AFP_OK );
 
1719
        volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV));
 
1720
    else
 
1721
        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV));
 
1722
    if (volume->v_cdb == NULL) {
 
1723
        LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID or invalid CNID backend for %s: %s", 
 
1724
            volume->v_path, volume->v_cnidscheme);
 
1725
        ret = AFPERR_MISC;
 
1726
        goto openvol_err;
 
1727
    }
 
1728
 
 
1729
    /* Codepages */
 
1730
 
 
1731
    if (!volume->v_volcodepage)
 
1732
        volume->v_volcodepage = strdup("UTF8");
 
1733
 
 
1734
    if ( (charset_t) -1 == ( volume->v_volcharset = add_charset(volume->v_volcodepage)) ) {
 
1735
        LOG (log_error, logtype_afpd, "Setting codepage %s as volume codepage failed", volume->v_volcodepage);
 
1736
        ret = AFPERR_MISC;
 
1737
        goto openvol_err;
 
1738
    }
 
1739
 
 
1740
    if ( NULL == ( volume->v_vol = find_charset_functions(volume->v_volcodepage)) || volume->v_vol->flags & CHARSET_ICONV ) {
 
1741
        LOG (log_warning, logtype_afpd, "WARNING: volume encoding %s is *not* supported by netatalk, expect problems !!!!", volume->v_volcodepage);
 
1742
    }   
 
1743
 
 
1744
    if (!volume->v_maccodepage)
 
1745
        volume->v_maccodepage = strdup(obj->options.maccodepage);
 
1746
 
 
1747
    if ( (charset_t) -1 == ( volume->v_maccharset = add_charset(volume->v_maccodepage)) ) {
 
1748
        LOG (log_error, logtype_afpd, "Setting codepage %s as mac codepage failed", volume->v_maccodepage);
 
1749
        ret = AFPERR_MISC;
 
1750
        goto openvol_err;
 
1751
    }
 
1752
 
 
1753
    if ( NULL == ( volume->v_mac = find_charset_functions(volume->v_maccodepage)) || ! (volume->v_mac->flags & CHARSET_CLIENT) ) {
 
1754
        LOG (log_error, logtype_afpd, "Fatal error: mac charset %s not supported", volume->v_maccodepage);
 
1755
        ret = AFPERR_MISC;
 
1756
        goto openvol_err;
 
1757
    }   
 
1758
 
 
1759
    ret  = stat_vol(bitmap, volume, rbuf, rbuflen);
 
1760
    if (ret == AFP_OK) {
 
1761
 
 
1762
        if (!(volume->v_flags & AFPVOL_RO)) {
 
1763
            handle_special_folders( volume );
 
1764
            savevoloptions( volume);
 
1765
        }
 
1766
 
 
1767
        /*
 
1768
         * If you mount a volume twice, the second time the trash appears on
 
1769
         * the desk-top.  That's because the Mac remembers the DID for the
 
1770
         * trash (even for volumes in different zones, on different servers).
 
1771
         * Just so this works better, we prime the DID cache with the trash,
 
1772
         * fixing the trash at DID 17.
 
1773
         * FIXME (RL): should it be done inside a CNID backend ? (always returning Trash DID when asked) ?
 
1774
         */
 
1775
        if ((volume->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
 
1776
 
 
1777
            /* FIXME find db time stamp */
 
1778
            if (cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) < 0) {
 
1779
                LOG (log_error, logtype_afpd, 
 
1780
                      "afp_openvol(%s): Fatal error: Unable to get stamp value from CNID backend",
 
1781
                      volume->v_path);
 
1782
                ret = AFPERR_MISC;
 
1783
                goto openvol_err;
 
1784
            }
 
1785
        }
 
1786
        else {
 
1787
            p = Trash;
 
1788
            cname( volume, volume->v_dir, &p );
 
1789
        }
 
1790
        return( AFP_OK );
 
1791
    }
1272
1792
 
1273
1793
openvol_err:
 
1794
    if (volume->v_dir) {
 
1795
        dirfree( volume->v_dir );
 
1796
        volume->v_dir = volume->v_root = NULL;
 
1797
    }
 
1798
 
 
1799
    volume->v_flags &= ~AFPVOL_OPEN;
 
1800
    if (volume->v_cdb != NULL) {
 
1801
        cnid_close(volume->v_cdb);
 
1802
        volume->v_cdb = NULL;
 
1803
    }
1274
1804
    *rbuflen = 0;
1275
1805
    return ret;
1276
1806
}
1277
1807
 
 
1808
/* ------------------------- */
 
1809
static void closevol(struct vol *vol)
 
1810
{
 
1811
    if (!vol)
 
1812
        return;
 
1813
 
 
1814
    dirfree( vol->v_root );
 
1815
    vol->v_dir = NULL;
 
1816
    if (vol->v_cdb != NULL) {
 
1817
        cnid_close(vol->v_cdb);
 
1818
        vol->v_cdb = NULL;
 
1819
    }
 
1820
 
 
1821
    if (vol->v_postexec) {
 
1822
        afprun(0, vol->v_postexec, NULL);
 
1823
    }
 
1824
    if (vol->v_root_postexec) {
 
1825
        afprun(1, vol->v_root_postexec, NULL);
 
1826
    }
 
1827
}
 
1828
 
 
1829
/* ------------------------- */
 
1830
void close_all_vol(void)
 
1831
{
 
1832
    struct vol  *ovol;
 
1833
    curdir = NULL;
 
1834
    for ( ovol = Volumes; ovol; ovol = ovol->v_next ) {
 
1835
        if ( (ovol->v_flags & AFPVOL_OPEN) ) {
 
1836
            ovol->v_flags &= ~AFPVOL_OPEN;
 
1837
            closevol(ovol);
 
1838
        }
 
1839
    }
 
1840
}
 
1841
 
 
1842
/* ------------------------- */
1278
1843
int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen )
1279
1844
AFPObj      *obj;
1280
1845
char    *ibuf, *rbuf;
1291
1856
    }
1292
1857
 
1293
1858
    vol->v_flags &= ~AFPVOL_OPEN;
1294
 
    for ( ovol = volumes; ovol; ovol = ovol->v_next ) {
1295
 
        if ( ovol->v_flags & AFPVOL_OPEN ) {
 
1859
    for ( ovol = Volumes; ovol; ovol = ovol->v_next ) {
 
1860
        if ( (ovol->v_flags & AFPVOL_OPEN) ) {
1296
1861
            break;
1297
1862
        }
1298
1863
    }
1302
1867
            curdir = ovol->v_dir;
1303
1868
        }
1304
1869
    }
1305
 
    dirfree( vol->v_root );
1306
 
    vol->v_dir = NULL;
1307
 
#ifdef CNID_DB
1308
 
    cnid_close(vol->v_db);
1309
 
    vol->v_db = NULL;
1310
 
#endif /* CNID_DB */
 
1870
 
 
1871
    closevol(vol);
 
1872
    if (vol->v_deleted) {
 
1873
        showvol(vol->v_name);
 
1874
        volume_free(vol);
 
1875
        volume_unlink(vol);
 
1876
        free(vol);
 
1877
    }
1311
1878
    return( AFP_OK );
1312
1879
}
1313
1880
 
 
1881
/* ------------------------- */
1314
1882
struct vol *getvolbyvid(const u_int16_t vid )
1315
1883
{
1316
1884
    struct vol  *vol;
1317
1885
 
1318
 
    for ( vol = volumes; vol; vol = vol->v_next ) {
 
1886
    for ( vol = Volumes; vol; vol = vol->v_next ) {
1319
1887
        if ( vid == vol->v_vid ) {
1320
1888
            break;
1321
1889
        }
1344
1912
    struct extmap *em;
1345
1913
 
1346
1914
    if (NULL == ( p = strrchr( path, '.' )) ) {
1347
 
        return( defextmap );
 
1915
        return( Defextmap );
1348
1916
    }
1349
1917
    p++;
1350
 
    if (!*p || !extmap_cnt) {
1351
 
        return( defextmap );
 
1918
    if (!*p || !Extmap_cnt) {
 
1919
        return( Defextmap );
1352
1920
    }
1353
 
    em = bsearch(p, extmap, extmap_cnt, sizeof(struct extmap), ext_cmp_key);
 
1921
    em = bsearch(p, Extmap, Extmap_cnt, sizeof(struct extmap), ext_cmp_key);
1354
1922
    if (em) {
1355
1923
        return( em );
1356
1924
    } else {
1357
 
        return( defextmap );
 
1925
        return( Defextmap );
1358
1926
    }
1359
1927
}
1360
1928
 
 
1929
/* ------------------------- */
1361
1930
struct extmap *getdefextmap(void)
1362
1931
{
1363
 
    return( defextmap );
 
1932
    return( Defextmap );
1364
1933
}
1365
1934
 
1366
 
/*
 
1935
/* --------------------------
1367
1936
   poll if a volume is changed by other processes.
1368
1937
*/
1369
1938
int  pollvoltime(obj)
1379
1948
    if ( gettimeofday( &tv, 0 ) < 0 ) 
1380
1949
         return 0;
1381
1950
 
1382
 
    for ( vol = volumes; vol; vol = vol->v_next ) {
1383
 
        if ( (vol->v_flags & AFPVOL_OPEN)  && vol->v_time + 30 < tv.tv_sec) {
1384
 
            if ( !stat( vol->v_path, &st ) && vol->v_time != st.st_mtime ) {
1385
 
                vol->v_time = st.st_mtime;
1386
 
                obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
 
1951
    for ( vol = Volumes; vol; vol = vol->v_next ) {
 
1952
        if ( (vol->v_flags & AFPVOL_OPEN)  && vol->v_mtime + 30 < tv.tv_sec) {
 
1953
            if ( !stat( vol->v_path, &st ) && vol->v_mtime != st.st_mtime ) {
 
1954
                vol->v_mtime = st.st_mtime;
 
1955
                if (!obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED))
 
1956
                    return -1;
1387
1957
                return 1;
1388
1958
            }
1389
1959
        }
1391
1961
    return 0;
1392
1962
}
1393
1963
 
 
1964
/* ------------------------- */
1394
1965
void setvoltime(obj, vol )
1395
1966
AFPObj *obj;
1396
1967
struct vol      *vol;
1397
1968
{
1398
1969
    struct timeval      tv;
1399
1970
 
1400
 
    /* just looking at vol->v_time is broken seriously since updates
 
1971
    /* just looking at vol->v_mtime is broken seriously since updates
1401
1972
     * from other users afpd processes never are seen.
1402
1973
     * This is not the most elegant solution (a shared memory between
1403
1974
     * the afpd processes would come closer)
1404
1975
     * [RS] */
1405
1976
 
1406
1977
    if ( gettimeofday( &tv, 0 ) < 0 ) {
1407
 
        LOG(log_error, logtype_afpd, "setvoltime: gettimeofday: %s", strerror(errno) );
 
1978
        LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) );
1408
1979
        return;
1409
1980
    }
1410
1981
    if( utime( vol->v_path, NULL ) < 0 ) {
1414
1985
    }
1415
1986
 
1416
1987
    /* a little granularity */
1417
 
    if (vol->v_time < tv.tv_sec) {
1418
 
        vol->v_time = tv.tv_sec;
 
1988
    if (vol->v_mtime < tv.tv_sec) {
 
1989
        vol->v_mtime = tv.tv_sec;
 
1990
        /* or finder doesn't update free space */
1419
1991
        if (afp_version > 21 && obj->options.server_notif) {
1420
1992
            obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
1421
1993
        }
1422
1994
    }
1423
1995
}
1424
1996
 
 
1997
/* ------------------------- */
1425
1998
int afp_getvolparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1426
1999
AFPObj      *obj;
1427
2000
char    *ibuf, *rbuf;
1428
2001
int             ibuflen, *rbuflen;
1429
2002
{
1430
 
    struct stat st;
1431
2003
    struct vol  *vol;
1432
 
    int         buflen, ret;
1433
2004
    u_int16_t   vid, bitmap;
1434
2005
 
1435
2006
    ibuf += 2;
1443
2014
        return( AFPERR_PARAM );
1444
2015
    }
1445
2016
 
1446
 
    if ( stat( vol->v_path, &st ) < 0 ) {
1447
 
        *rbuflen = 0;
1448
 
        return( AFPERR_PARAM );
1449
 
    }
1450
 
 
1451
 
    buflen = *rbuflen - sizeof( bitmap );
1452
 
    if (( ret = getvolparams( bitmap, vol, &st,
1453
 
                              rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) {
1454
 
        *rbuflen = 0;
1455
 
        return( ret );
1456
 
    }
1457
 
    *rbuflen = buflen + sizeof( bitmap );
1458
 
    bitmap = htons( bitmap );
1459
 
    memcpy(rbuf, &bitmap, sizeof( bitmap ));
1460
 
    return( AFP_OK );
 
2017
    return stat_vol(bitmap, vol, rbuf, rbuflen);
1461
2018
}
1462
2019
 
 
2020
/* ------------------------- */
1463
2021
int afp_setvolparams(obj, ibuf, ibuflen, rbuf, rbuflen )
1464
2022
AFPObj      *obj;
1465
2023
char    *ibuf, *rbuf;
1483
2041
        return( AFPERR_PARAM );
1484
2042
    }
1485
2043
 
1486
 
    if (vol->v_flags & AFPVOL_RO)
 
2044
    if ((vol->v_flags & AFPVOL_RO))
1487
2045
        return AFPERR_VLOCK;
1488
2046
 
1489
2047
    /* we can only set the backup date. */
1490
 
    if (bitmap != VOLPBIT_BDATE)
 
2048
    if (bitmap != (1 << VOLPBIT_BDATE))
1491
2049
        return AFPERR_BITMAP;
1492
2050
 
1493
 
    memset(&ad, 0, sizeof(ad));
 
2051
    ad_init(&ad, vol->v_adouble, vol->v_ad_options);
1494
2052
    if ( ad_open( vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR,
1495
2053
                  0666, &ad) < 0 ) {
1496
2054
        if (errno == EROFS)
1506
2064
    return( AFP_OK );
1507
2065
}
1508
2066
 
1509
 
 
 
2067
/* ------------------------- */
1510
2068
int wincheck(const struct vol *vol, const char *path)
1511
2069
{
1512
2070
    int len;
1531
2089
    /* everything else is okay */
1532
2090
    return 1;
1533
2091
}
 
2092
 
 
2093
 
 
2094
/*
 
2095
 * precreate a folder 
 
2096
 * this is only intended for folders in the volume root 
 
2097
 * It will *not* work if the folder name contains extended characters 
 
2098
 */
 
2099
static int create_special_folder (const struct vol *vol, const struct _special_folder *folder)
 
2100
{
 
2101
        char            *p,*q,*r;
 
2102
        struct adouble  ad;
 
2103
        u_int16_t       attr;
 
2104
        struct stat     st;
 
2105
        int             ret;
 
2106
 
 
2107
 
 
2108
        p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2);
 
2109
        if ( p == NULL) {
 
2110
                LOG(log_error, logtype_afpd,"malloc failed");
 
2111
                exit (EXITERR_SYS);
 
2112
        }
 
2113
 
 
2114
        q=strdup(folder->name);
 
2115
        if ( q == NULL) {
 
2116
                LOG(log_error, logtype_afpd,"malloc failed");
 
2117
                exit (EXITERR_SYS);
 
2118
        }
 
2119
 
 
2120
        strcpy(p, vol->v_path);
 
2121
        strcat(p, "/");
 
2122
 
 
2123
        r=q;
 
2124
        while (*r) {
 
2125
                if ((vol->v_casefold & AFPVOL_MTOUUPPER))
 
2126
                        *r=toupper(*r);
 
2127
                else if ((vol->v_casefold & AFPVOL_MTOULOWER))
 
2128
                        *r=tolower(*r);
 
2129
                r++;
 
2130
        }
 
2131
        strcat(p, q);
 
2132
 
 
2133
        if ( (ret = stat( p, &st )) < 0 ) {
 
2134
                if (folder->precreate) {
 
2135
                    if (ad_mkdir(p, folder->mode)) {
 
2136
                        LOG(log_debug, logtype_afpd,"Creating '%s' failed in %s: %s", p, vol->v_path, strerror(errno));
 
2137
                        free(p);
 
2138
                        free(q);
 
2139
                        return -1;
 
2140
                    }
 
2141
                    ret = 0;
 
2142
                }
 
2143
        }
 
2144
 
 
2145
        if ( !ret && folder->hide) {
 
2146
                /* Hide it */
 
2147
                ad_init(&ad, vol->v_adouble, vol->v_ad_options);
 
2148
                if (ad_open( p, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR,
 
2149
                        O_RDWR|O_CREAT, 0666, &ad) < 0) {
 
2150
                        free (p);
 
2151
                        free(q);
 
2152
                        return (-1);
 
2153
                }
 
2154
                if ((ad_get_HF_flags( &ad ) & O_CREAT) ) {
 
2155
                    if (ad_getentryoff(&ad, ADEID_NAME)) {
 
2156
                        ad_setentrylen( &ad, ADEID_NAME, strlen(folder->name));
 
2157
                        memcpy(ad_entry( &ad, ADEID_NAME ), folder->name,
 
2158
                               ad_getentrylen( &ad, ADEID_NAME ));
 
2159
                    }
 
2160
                }
 
2161
 
 
2162
                ad_getattr(&ad, &attr);
 
2163
                attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE );
 
2164
                ad_setattr(&ad, attr);
 
2165
#if 0           
 
2166
                /* do the same with the finder info */
 
2167
                if (ad_entry(&ad, ADEID_FINDERI)) {
 
2168
                        memcpy(&attr, ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, sizeof(attr));
 
2169
                        attr   |= htons(FINDERINFO_INVISIBLE);
 
2170
                        memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr));
 
2171
                }
 
2172
#endif    
 
2173
                ad_flush( &ad, ADFLAGS_HF );
 
2174
                ad_close( &ad, ADFLAGS_HF );
 
2175
        }
 
2176
        free(p);
 
2177
        free(q);
 
2178
        return 0;
 
2179
}
 
2180
 
 
2181
static void handle_special_folders (const struct vol * vol)
 
2182
{
 
2183
        const _special_folder *p = &special_folders[0];
 
2184
 
 
2185
        if ((vol->v_flags & AFPVOL_RO))
 
2186
                return;
 
2187
 
 
2188
        for (; p->name != NULL; p++) {
 
2189
                create_special_folder (vol, p);
 
2190
        }
 
2191
}
 
2192
 
 
2193
/*
 
2194
 * Save the volume options to a file, used by
 
2195
 * shell utilities.
 
2196
 * Writing the file everytime a volume is opened is
 
2197
 * unnecessary, but it shouldn't hurt much.
 
2198
 */
 
2199
static int savevoloptions (const struct vol *vol)
 
2200
{
 
2201
    char buf[16348];
 
2202
    char item[MAXPATHLEN];
 
2203
    int fd;
 
2204
    int ret = 0;
 
2205
    struct flock lock;
 
2206
    const _vol_opt_name *op = &vol_opt_names[0];
 
2207
    const _vol_opt_name *cf = &vol_opt_casefold[0];
 
2208
 
 
2209
    strlcpy (item, vol->v_path, sizeof(item));
 
2210
    strlcat (item, "/.AppleDesktop/", sizeof(item));
 
2211
    strlcat (item, VOLINFOFILE, sizeof(item));
 
2212
 
 
2213
    if ((fd = open( item, O_RDWR | O_CREAT , 0666)) <0 ) {
 
2214
        LOG(log_debug, logtype_afpd,"Error opening %s: %s", item, strerror(errno));
 
2215
        return (-1);
 
2216
    }
 
2217
 
 
2218
    /* try to get a lock */
 
2219
    lock.l_start  = 0;
 
2220
    lock.l_whence = SEEK_SET;
 
2221
    lock.l_len    = 0;
 
2222
    lock.l_type   = F_WRLCK;
 
2223
 
 
2224
    if (fcntl(fd, F_SETLK, &lock) < 0) {
 
2225
        if (errno == EACCES || errno == EAGAIN) {
 
2226
            /* ignore, other process already writing the file */
 
2227
            return 0;
 
2228
        } else {
 
2229
            LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno));
 
2230
            return (-1);
 
2231
        }
 
2232
    }
 
2233
 
 
2234
    /* write volume options */
 
2235
    snprintf(buf, sizeof(buf), "MAC_CHARSET:%s\n", vol->v_maccodepage);
 
2236
    snprintf(item, sizeof(item), "VOL_CHARSET:%s\n", vol->v_volcodepage);
 
2237
    strlcat(buf, item, sizeof(buf));
 
2238
 
 
2239
    switch (vol->v_adouble) {
 
2240
        case AD_VERSION1:
 
2241
            strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf));
 
2242
            break;
 
2243
        case AD_VERSION2:
 
2244
            strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf));
 
2245
            break;
 
2246
        case AD_VERSION2_OSX:
 
2247
            strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf));
 
2248
            break;
 
2249
    }
 
2250
 
 
2251
    strlcat(buf, "CNIDBACKEND:", sizeof(buf));
 
2252
    strlcat(buf, vol->v_cnidscheme, sizeof(buf));
 
2253
    strlcat(buf, "\n", sizeof(buf));
 
2254
 
 
2255
    strlcat(buf, "CNIDDBDHOST:", sizeof(buf));
 
2256
    strlcat(buf, Cnid_srv, sizeof(buf));
 
2257
    strlcat(buf, "\n", sizeof(buf));
 
2258
 
 
2259
    snprintf(item, sizeof(item), "CNIDDBDPORT:%u\n", Cnid_port);
 
2260
    strlcat(buf, item, sizeof(buf));
 
2261
 
 
2262
    strcpy(item, "CNID_DBPATH:");
 
2263
    if (vol->v_dbpath)
 
2264
        strlcat(item, vol->v_dbpath, sizeof(item));
 
2265
    else
 
2266
        strlcat(item, vol->v_path, sizeof(item));
 
2267
    strlcat(item, "\n", sizeof(item));
 
2268
    strlcat(buf, item, sizeof(buf));
 
2269
 
 
2270
    /* volume flags */
 
2271
    strcpy(item, "VOLUME_OPTS:");
 
2272
    for (;op->name; op++) {
 
2273
        if ( (vol->v_flags & op->option) ) {
 
2274
            strlcat(item, op->name, sizeof(item));
 
2275
            strlcat(item, " ", sizeof(item));
 
2276
        }
 
2277
    }
 
2278
    strlcat(item, "\n", sizeof(item));
 
2279
    strlcat(buf, item, sizeof(buf));
 
2280
 
 
2281
    /* casefold flags */
 
2282
    strcpy(item, "VOLCASEFOLD:");
 
2283
    for (;cf->name; cf++) {
 
2284
        if ( (vol->v_casefold & cf->option) ) {
 
2285
            strlcat(item, cf->name, sizeof(item));
 
2286
            strlcat(item, " ", sizeof(item));
 
2287
        }
 
2288
    }
 
2289
    strlcat(item, "\n", sizeof(item));
 
2290
    strlcat(buf, item, sizeof(buf));
 
2291
 
 
2292
    if (strlen(buf) >= sizeof(buf)-1)
 
2293
        LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf);
 
2294
 
 
2295
 
 
2296
   if (write( fd, buf, strlen(buf)) < 0) {
 
2297
       LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
 
2298
       goto done;
 
2299
   }
 
2300
   ftruncate(fd, strlen(buf));
 
2301
 
 
2302
done:
 
2303
   lock.l_type = F_UNLCK;
 
2304
   fcntl(fd, F_SETLK, &lock);
 
2305
   close (fd);
 
2306
   return ret;
 
2307
}