134
typedef struct _special_folder {
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},
146
{"TheFindByContentFolder", 0, 0, 1},
147
{"TheVolumeSettingsFolder", 0, 0, 1},
151
typedef struct _volopt_name {
152
const u_int32_t option;
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 */
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"},
183
static void handle_special_folders (const struct vol *);
184
static int savevoloptions (const struct vol *);
130
186
static __inline__ void volfree(struct vol_option *options,
131
187
const struct vol_option *save)
267
351
/* to make sure that val is valid, make sure to select an opt that
269
#define optionok(buf,opt,val) (strstr((buf),(opt)) && ((val)[1] != '\0'))
271
static __inline__ char *get_codepage_path(const char *path, const char *name)
277
page = (char *) malloc((len = strlen(path)) + strlen(name) + 2);
280
if (path[len - 1] != '/') /* add a / */
288
/* debug: show which codepage directory we are using */
289
LOG(log_debug, logtype_afpd, "using codepage directory: %s", page);
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,
353
static int optionok(const char *buf, const char *opt, const char *val)
355
if (!strstr(buf,opt))
363
/* -------------------- */
364
static void setoption(struct vol_option *options, struct vol_option *save, int opt, const char *val)
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);
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,
301
LOG(log_debug, logtype_afpd, "Parsing volset %s", tmp);
303
379
val = strchr(tmp, ':');
305
381
/* we'll assume it's a volume name. */
306
382
strncpy(volname, tmp, vlen);
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);
387
LOG(log_debug, logtype_afpd, "Parsing volset %s", val);
389
if (optionok(tmp, "allow:", val)) {
390
setoption(options, save, VOLOPT_ALLOW, val);
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);
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);
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);
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);
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 */
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);
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;
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;
383
474
p = strtok(NULL, ",");
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);
392
volxlate(obj, t, MAXPATHLEN, val, pwd, NULL);
393
options[VOLOPT_DBPATH].c_value = strdup(t + 1);
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);
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);
407
488
#ifdef FORCE_UIDGID
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);
419
496
#endif /* FORCE_UIDGID */
497
} else if (optionok(tmp, "root_preexec:", val)) {
498
setoption(options, save, VOLOPT_ROOTPREEXEC, val);
500
} else if (optionok(tmp, "preexec:", val)) {
501
setoption(options, save, VOLOPT_PREEXEC, val);
503
} else if (optionok(tmp, "root_postexec:", val)) {
504
setoption(options, save, VOLOPT_ROOTPOSTEXEC, val);
506
} else if (optionok(tmp, "postexec:", val)) {
507
setoption(options, save, VOLOPT_POSTEXEC, val);
422
510
/* ignore unknown options */
423
511
LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp);
428
static int creatvol(const char *path, char *name, struct vol_option *options)
516
/* ----------------- */
517
static void showvol(const ucs2_t *name)
520
for ( volume = Volumes; volume; volume = volume->v_next ) {
521
if (volume->v_hide && !strcasecmp_w( volume->v_name, name ) ) {
529
* FIXME should be define elsewhere
531
static int validupath_adouble(const struct vol *vol, const char *name)
533
return (vol->v_flags & AFPVOL_USEDOTS) ? strncasecmp(name,".Apple", 6) && strcasecmp(name, ".Parent")
537
/* ----------------- */
538
static int validupath_osx(const struct vol *vol, const char *name)
540
return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2);
543
/* ---------------- */
544
static void initvoladouble(struct vol *vol)
546
if (vol->v_adouble == AD_VERSION2_OSX) {
547
vol->validupath = validupath_osx;
548
vol->ad_path = ad_path_osx;
551
vol->validupath = validupath_adouble;
552
vol->ad_path = ad_path;
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 */
430
563
struct vol *volume;
433
568
if ( name == NULL || *name == '\0' ) {
434
569
if ((name = strrchr( path, '/' )) == NULL) {
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... */
449
578
vlen = strlen( name );
450
579
if ( vlen > AFPVOL_NAMELEN ) {
451
580
vlen = AFPVOL_NAMELEN;
452
581
name[AFPVOL_NAMELEN] = '\0';
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)) )
588
for ( volume = Volumes; volume; volume = volume->v_next ) {
589
if ( strcasecmp_w( volume->v_name, tmpname ) == 0 ) {
590
if (volume->v_deleted) {
594
return -1; /* Won't be able to access it, anyway... */
600
if (!( volume = (struct vol *)calloc(1, sizeof( struct vol ))) ) {
457
601
LOG(log_error, logtype_afpd, "creatvol: malloc: %s", strerror(errno) );
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) );
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);
474
strcpy( volume->v_name, name);
615
volume->v_hide = hide;
475
616
strcpy( volume->v_path, path );
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);
483
625
/* handle options */
488
630
/* shift in some flags */
489
631
volume->v_flags = options[VOLOPT_FLAGS].i_value;
491
/* read in the code pages */
492
if (options[VOLOPT_CODEPAGE].c_value)
493
codepage_read(volume, options[VOLOPT_CODEPAGE].c_value);
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;
495
639
if (options[VOLOPT_PASSWORD].c_value)
496
640
volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value);
498
642
if (options[VOLOPT_VETO].c_value)
499
643
volume->v_veto = strdup(options[VOLOPT_VETO].c_value);
645
if (options[VOLOPT_ENCODING].c_value)
646
volume->v_volcodepage = strdup(options[VOLOPT_ENCODING].c_value);
648
if (options[VOLOPT_MACCHARSET].c_value)
649
volume->v_maccodepage = strdup(options[VOLOPT_MACCHARSET].c_value);
502
651
if (options[VOLOPT_DBPATH].c_value)
503
volume->v_dbpath = strdup(options[VOLOPT_DBPATH].c_value);
652
volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_DBPATH].c_value, pwd, path, name);
654
if (options[VOLOPT_CNIDSCHEME].c_value)
655
volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value);
506
657
if (options[VOLOPT_UMASK].i_value)
507
658
volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value;
660
if (options[VOLOPT_ADOUBLE].i_value)
661
volume->v_adouble = options[VOLOPT_ADOUBLE].i_value;
663
volume->v_adouble = AD_VERSION;
509
664
#ifdef FORCE_UIDGID
511
665
if (options[VOLOPT_FORCEUID].c_value) {
512
666
volume->v_forceuid = strdup(options[VOLOPT_FORCEUID].c_value);
832
1064
if ( fclose( fp ) != 0 ) {
833
1065
LOG(log_error, logtype_afpd, "readvolfile: fclose: %s", strerror(errno) );
839
static void load_volumes(AFPObj *obj)
841
struct passwd *pwent = getpwnam(obj->username);
843
if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
844
readvolfile(obj, obj->options.systemvol, NULL, 0, pwent);
847
if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
848
readvolfile(obj, obj->options.defaultvol, NULL, 1, pwent);
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.
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);
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)
1077
free(vol->v_password);
1079
free(vol->v_volcodepage);
1080
free(vol->v_maccodepage);
1081
free(vol->v_cnidscheme);
1082
free(vol->v_dbpath);
1085
free(vol->v_forceuid);
1086
free(vol->v_forcegid);
1087
#endif /* FORCE_UIDGID */
1090
/* ------------------------------- */
1091
static void free_volumes(void )
1094
struct vol *nvol, *ovol;
1096
for ( vol = Volumes; vol; vol = vol->v_next ) {
1097
if (( vol->v_flags & AFPVOL_OPEN ) ) {
1104
for ( vol = Volumes, ovol = NULL; vol; vol = nvol) {
1107
if (vol->v_name == NULL) {
1108
if (Volumes == vol) {
1113
ovol->v_next = nvol;
1123
/* ------------------------------- */
1124
static void volume_unlink(struct vol *volume)
1126
struct vol *vol, *ovol, *nvol;
1128
if (volume == Volumes) {
1129
Volumes = Volumes->v_next;
1132
for ( vol = Volumes->v_next, ovol = Volumes; vol; vol = nvol) {
1135
if (vol == volume) {
1136
ovol->v_next = nvol;
936
1235
* For MacOS8.x support we need to create the
937
1236
* .Parent file here if it doesn't exist. */
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 ) {
1243
vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
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, '/' );
950
1250
slash = vol->v_path;
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);
1256
vol_setdate(vol->v_vid, &ad, st->st_mtime);
956
1257
ad_flush(&ad, ADFLAGS_HF);
1260
if (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0)
1261
vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
1263
vol->v_ctime = aint;
959
1266
if (( bitmap & ( (1<<VOLPBIT_BFREE)|(1<<VOLPBIT_BTOTAL) |
960
1267
(1<<VOLPBIT_XBFREE)|(1<<VOLPBIT_XBTOTAL) |
1101
1414
return( AFP_OK );
1417
/* ------------------------- */
1418
static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen)
1423
if ( stat( vol->v_path, &st ) < 0 ) {
1425
return( AFPERR_PARAM );
1427
/* save the volume device number */
1428
vol->v_dev = st.st_dev;
1430
buflen = *rbuflen - sizeof( bitmap );
1431
if (( ret = getvolparams( bitmap, vol, &st,
1432
rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) {
1436
*rbuflen = buflen + sizeof( bitmap );
1437
bitmap = htons( bitmap );
1438
memcpy(rbuf, &bitmap, sizeof( bitmap ));
1443
/* ------------------------------- */
1444
void load_volumes(AFPObj *obj)
1446
struct passwd *pwent;
1451
/* check files date */
1452
if (obj->options.defaultvol.loaded) {
1453
changed = volfile_changed(&obj->options.defaultvol);
1455
if (obj->options.systemvol.loaded) {
1456
changed |= volfile_changed(&obj->options.systemvol);
1458
if (obj->options.uservol.loaded) {
1459
changed |= volfile_changed(&obj->options.uservol);
1468
pwent = getpwnam(obj->username);
1469
if ( (obj->options.flags & OPTION_USERVOLFIRST) == 0 ) {
1470
readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent);
1473
if ((*obj->username == '\0') || (obj->options.flags & OPTION_NOUSERVOL)) {
1474
readvolfile(obj, &obj->options.defaultvol, NULL, 1, pwent);
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.
1481
if (obj->options.uservol.name) {
1482
free(obj->options.uservol.name);
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);
1494
if ( obj->options.flags & OPTION_USERVOLFIRST ) {
1495
readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent );
1499
/* ------------------------------- */
1106
1500
int afp_getsrvrparms(obj, ibuf, ibuflen, rbuf, rbuflen )
1108
1502
char *ibuf, *rbuf;
1168
1575
struct stat st;
1172
#endif /* CNID_DB */
1173
1578
struct vol *volume;
1174
1579
struct dir *dir;
1175
int len, ret, buflen;
1176
1582
u_int16_t bitmap;
1583
char path[ MAXPATHLEN + 1];
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;
1593
return AFPERR_BITMAP;
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));
1602
return AFPERR_PARAM;
1192
1606
if ((len + 1) & 1) /* pad to an even boundary */
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 ) {
1204
1617
if ( volume == NULL ) {
1619
return AFPERR_PARAM;
1209
1622
/* check for a volume password */
1210
if (volume->v_password &&
1211
strncmp(ibuf, volume->v_password, VOLPASSLEN)) {
1212
ret = AFPERR_ACCESS;
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)) {
1625
return AFPERR_ACCESS;
1628
if (( volume->v_flags & AFPVOL_OPEN ) ) {
1629
/* the volume is already open */
1631
set_uidgid ( volume );
1633
return stat_vol(bitmap, volume, rbuf, rbuflen);
1636
/* initialize volume variables
1639
if (afp_version >= 30) {
1640
volume->max_filename = 255;
1643
volume->max_filename = MACFILELEN;
1646
volume->v_dir = volume->v_root = NULL;
1648
volume->v_flags |= AFPVOL_OPEN;
1649
volume->v_cdb = NULL;
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;
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;
1228
1659
#ifdef FORCE_UIDGID
1229
1660
set_uidgid ( volume );
1230
#endif /* FORCE_UIDGID */
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 );
1232
1671
if ( stat( volume->v_path, &st ) < 0 ) {
1233
1672
ret = AFPERR_PARAM;
1234
1673
goto openvol_err;
1237
buflen = *rbuflen - sizeof( bitmap );
1238
if (( ret = getvolparams( bitmap, volume, &st,
1239
rbuf + sizeof(bitmap), &buflen )) != AFP_OK ) {
1242
*rbuflen = buflen + sizeof( bitmap );
1243
bitmap = htons( bitmap );
1244
memcpy(rbuf, &bitmap, sizeof( bitmap ));
1246
1676
if ( chdir( volume->v_path ) < 0 ) {
1247
1677
ret = AFPERR_PARAM;
1248
1678
goto openvol_err;
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) {
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);
1695
if ((vol_uname = strrchr(path, '/')) == NULL)
1697
else if (*(vol_uname + 1) != '\0')
1700
if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) {
1702
LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) );
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;
1250
1712
curdir = volume->v_dir;
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.",
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 */
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.
1268
cname( volume, volume->v_dir, &p );
1269
#endif /* CNID_DB */
1719
volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV));
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);
1731
if (!volume->v_volcodepage)
1732
volume->v_volcodepage = strdup("UTF8");
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);
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);
1744
if (!volume->v_maccodepage)
1745
volume->v_maccodepage = strdup(obj->options.maccodepage);
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);
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);
1759
ret = stat_vol(bitmap, volume, rbuf, rbuflen);
1760
if (ret == AFP_OK) {
1762
if (!(volume->v_flags & AFPVOL_RO)) {
1763
handle_special_folders( volume );
1764
savevoloptions( volume);
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) ?
1775
if ((volume->v_cdb->flags & CNID_FLAG_PERSISTENT)) {
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",
1788
cname( volume, volume->v_dir, &p );
1794
if (volume->v_dir) {
1795
dirfree( volume->v_dir );
1796
volume->v_dir = volume->v_root = NULL;
1799
volume->v_flags &= ~AFPVOL_OPEN;
1800
if (volume->v_cdb != NULL) {
1801
cnid_close(volume->v_cdb);
1802
volume->v_cdb = NULL;
1808
/* ------------------------- */
1809
static void closevol(struct vol *vol)
1814
dirfree( vol->v_root );
1816
if (vol->v_cdb != NULL) {
1817
cnid_close(vol->v_cdb);
1821
if (vol->v_postexec) {
1822
afprun(0, vol->v_postexec, NULL);
1824
if (vol->v_root_postexec) {
1825
afprun(1, vol->v_root_postexec, NULL);
1829
/* ------------------------- */
1830
void close_all_vol(void)
1834
for ( ovol = Volumes; ovol; ovol = ovol->v_next ) {
1835
if ( (ovol->v_flags & AFPVOL_OPEN) ) {
1836
ovol->v_flags &= ~AFPVOL_OPEN;
1842
/* ------------------------- */
1278
1843
int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen )
1280
1845
char *ibuf, *rbuf;
1531
2089
/* everything else is okay */
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
2099
static int create_special_folder (const struct vol *vol, const struct _special_folder *folder)
2108
p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2);
2110
LOG(log_error, logtype_afpd,"malloc failed");
2114
q=strdup(folder->name);
2116
LOG(log_error, logtype_afpd,"malloc failed");
2120
strcpy(p, vol->v_path);
2125
if ((vol->v_casefold & AFPVOL_MTOUUPPER))
2127
else if ((vol->v_casefold & AFPVOL_MTOULOWER))
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));
2145
if ( !ret && folder->hide) {
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) {
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 ));
2162
ad_getattr(&ad, &attr);
2163
attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE );
2164
ad_setattr(&ad, attr);
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));
2173
ad_flush( &ad, ADFLAGS_HF );
2174
ad_close( &ad, ADFLAGS_HF );
2181
static void handle_special_folders (const struct vol * vol)
2183
const _special_folder *p = &special_folders[0];
2185
if ((vol->v_flags & AFPVOL_RO))
2188
for (; p->name != NULL; p++) {
2189
create_special_folder (vol, p);
2194
* Save the volume options to a file, used by
2196
* Writing the file everytime a volume is opened is
2197
* unnecessary, but it shouldn't hurt much.
2199
static int savevoloptions (const struct vol *vol)
2202
char item[MAXPATHLEN];
2206
const _vol_opt_name *op = &vol_opt_names[0];
2207
const _vol_opt_name *cf = &vol_opt_casefold[0];
2209
strlcpy (item, vol->v_path, sizeof(item));
2210
strlcat (item, "/.AppleDesktop/", sizeof(item));
2211
strlcat (item, VOLINFOFILE, sizeof(item));
2213
if ((fd = open( item, O_RDWR | O_CREAT , 0666)) <0 ) {
2214
LOG(log_debug, logtype_afpd,"Error opening %s: %s", item, strerror(errno));
2218
/* try to get a lock */
2220
lock.l_whence = SEEK_SET;
2222
lock.l_type = F_WRLCK;
2224
if (fcntl(fd, F_SETLK, &lock) < 0) {
2225
if (errno == EACCES || errno == EAGAIN) {
2226
/* ignore, other process already writing the file */
2229
LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno));
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));
2239
switch (vol->v_adouble) {
2241
strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf));
2244
strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf));
2246
case AD_VERSION2_OSX:
2247
strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf));
2251
strlcat(buf, "CNIDBACKEND:", sizeof(buf));
2252
strlcat(buf, vol->v_cnidscheme, sizeof(buf));
2253
strlcat(buf, "\n", sizeof(buf));
2255
strlcat(buf, "CNIDDBDHOST:", sizeof(buf));
2256
strlcat(buf, Cnid_srv, sizeof(buf));
2257
strlcat(buf, "\n", sizeof(buf));
2259
snprintf(item, sizeof(item), "CNIDDBDPORT:%u\n", Cnid_port);
2260
strlcat(buf, item, sizeof(buf));
2262
strcpy(item, "CNID_DBPATH:");
2264
strlcat(item, vol->v_dbpath, sizeof(item));
2266
strlcat(item, vol->v_path, sizeof(item));
2267
strlcat(item, "\n", sizeof(item));
2268
strlcat(buf, item, sizeof(buf));
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));
2278
strlcat(item, "\n", sizeof(item));
2279
strlcat(buf, item, sizeof(buf));
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));
2289
strlcat(item, "\n", sizeof(item));
2290
strlcat(buf, item, sizeof(buf));
2292
if (strlen(buf) >= sizeof(buf)-1)
2293
LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf);
2296
if (write( fd, buf, strlen(buf)) < 0) {
2297
LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno));
2300
ftruncate(fd, strlen(buf));
2303
lock.l_type = F_UNLCK;
2304
fcntl(fd, F_SETLK, &lock);