X-Git-Url: https://arthur.barton.de/gitweb/?a=blobdiff_plain;f=etc%2Fafpd%2Fvolume.c;h=53a0bc23ee4c123fd106dc4058e729cf05edf03a;hb=85e784fb876d3cc1e907b49421a15a40ba9adf98;hp=86248a75a57b0ed2e0b0c97f9a0dfeb01e8f60b9;hpb=123d1541e5f8bf7af3c25e5f8e1b0d007f5c7919;p=netatalk.git diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 86248a75..53a0bc23 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -1,5 +1,5 @@ /* - * $Id: volume.c,v 1.51.2.7.2.14 2003-12-17 17:19:20 lenneis Exp $ + * $Id: volume.c,v 1.51.2.7.2.33.2.19 2009-01-28 05:37:58 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -17,9 +17,6 @@ #include #include #include -#ifdef HAVE_FCNTL_H -#include -#endif /* HAVE_FCNTL_H */ #ifdef HAVE_STRINGS_H #include #endif @@ -37,14 +34,10 @@ char *strchr (), *strrchr (); #define memmove(d,s,n) bcopy ((s), (d), (n)) #endif /* ! HAVE_MEMCPY */ #endif /* STDC_HEADERS */ -#include -#include -#include #include #include #include #include -#include #include #include #include @@ -121,12 +114,14 @@ m=u -> map both ways #define VOLOPT_FORCEUID 19 /* force uid for username x */ #define VOLOPT_FORCEGID 20 /* force gid for group x */ -#define VOLOPT_UMASK 21 -#else -#define VOLOPT_UMASK 19 #endif /* FORCE_UIDGID */ -#define VOLOPT_MAX (VOLOPT_UMASK +1) +#define VOLOPT_UMASK 21 +#define VOLOPT_DPERM 22 /* dperm default directories perms */ +#define VOLOPT_FPERM 23 /* dperm default files perms */ +#define VOLOPT_DFLTPERM 24 /* perm */ + +#define VOLOPT_MAX (VOLOPT_DFLTPERM +1) #define VOLOPT_NUM (VOLOPT_MAX + 1) @@ -148,15 +143,51 @@ typedef struct _special_folder { static const _special_folder special_folders[] = { {"Network Trash Folder", 1, 0777, 1}, {"Temporary Items", 1, 0777, 1}, + {".AppleDesktop", 1, 0777, 0}, #if 0 {"TheFindByContentFolder", 0, 0, 1}, {"TheVolumeSettingsFolder", 0, 0, 1}, #endif {NULL, 0, 0, 0}}; +typedef struct _volopt_name { + const u_int32_t option; + const char *name; +} _vol_opt_name; + +static const _vol_opt_name vol_opt_names[] = { + {AFPVOL_A2VOL, "PRODOS"}, /* prodos volume */ + {AFPVOL_CRLF, "CRLF"}, /* cr/lf translation */ + {AFPVOL_NOADOUBLE, "NOADOUBLE"}, /* don't create .AppleDouble by default */ + {AFPVOL_RO, "READONLY"}, /* read-only volume */ + {AFPVOL_MSWINDOWS, "MSWINDOWS"}, /* deal with ms-windows yuckiness. this is going away. */ + {AFPVOL_NOHEX, "NOHEX"}, /* don't do :hex translation */ + {AFPVOL_USEDOTS, "USEDOTS"}, /* use real dots */ + {AFPVOL_LIMITSIZE, "LIMITSIZE"}, /* limit size for older macs */ + {AFPVOL_MAPASCII, "MAPASCII"}, /* map the ascii range as well */ + {AFPVOL_DROPBOX, "DROPBOX"}, /* dropkludge dropbox support */ + {AFPVOL_NOFILEID, "NOFILEID"}, /* don't advertise createid resolveid and deleteid calls */ + {AFPVOL_NOSTAT, "NOSTAT"}, /* advertise the volume even if we can't stat() it + * maybe because it will be mounted later in preexec */ + {AFPVOL_UNIX_PRIV, "UNIXPRIV"}, /* support unix privileges */ + {AFPVOL_NODEV, "NODEV"}, /* always use 0 for device number in cnid calls */ + {AFPVOL_EILSEQ, "ILLEGALSEQ"}, /* encode illegal sequence */ + {AFPVOL_CACHE, "CACHEID"}, /* Use adouble v2 CNID caching, default don't use it */ + {0, NULL} +}; + +static const _vol_opt_name vol_opt_casefold[] = { + {AFPVOL_MTOUUPPER, "MTOULOWER"}, + {AFPVOL_MTOULOWER, "MTOULOWER"}, + {AFPVOL_UTOMUPPER, "UTOMUPPER"}, + {AFPVOL_UTOMLOWER, "UTOMLOWER"}, + {0, NULL} +}; + static void handle_special_folders (const struct vol *); +static int savevoloptions (const struct vol *); -static __inline__ void volfree(struct vol_option *options, +static void volfree(struct vol_option *options, const struct vol_option *save) { int i; @@ -185,14 +216,16 @@ static __inline__ void volfree(struct vol_option *options, * $i -> client ip/appletalk address without port * $s -> server name (hostname if it doesn't exist) * $u -> username (guest is usually nobody) - * $v -> volume name (ADEID_NAME or basename if ADEID_NAME is empty) + * $v -> volume name or basename if null * $z -> zone (may not exist) * $$ -> $ + * + * */ #define is_var(a, b) (strncmp((a), (b), 2) == 0) static char *volxlate(AFPObj *obj, char *dest, size_t destlen, - char *src, struct passwd *pwd, char *path) + char *src, struct passwd *pwd, char *path, char *volname) { char *p, *q; int len; @@ -208,12 +241,12 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, if (!ret) { return NULL; } - strncpy(dest, src, destlen); + strlcpy(dest, src, destlen +1); if ((p = strchr(src, '$')) == NULL) /* nothing to do */ return ret; /* first part of the path. just forward to the next variable. */ - len = MIN(p - src, destlen); + len = MIN((size_t)(p - src), destlen); if (len > 0) { destlen -= len; dest += len; @@ -281,26 +314,14 @@ static char *volxlate(AFPObj *obj, char *dest, size_t destlen, } else if (is_var(p, "$u")) { q = obj->username; } else if (is_var(p, "$v")) { - if (path) { - struct adouble ad; - - ad_init(&ad, 0); - if (ad_open(path, ADFLAGS_HF, O_RDONLY, 0, &ad) < 0) - goto no_volname; - - if ((len = MIN(ad_getentrylen(&ad, ADEID_NAME), destlen)) > 0) { - memcpy(dest, ad_entry(&ad, ADEID_NAME), len); - ad_close(&ad, ADFLAGS_HF); - dest += len; - destlen -= len; - } else { - ad_close(&ad, ADFLAGS_HF); -no_volname: /* simple basename */ - if ((q = strrchr(path, '/')) == NULL) - q = path; - else if (*(q + 1) != '\0') - q++; - } + if (volname) { + q = volname; + } + else if (path) { + if ((q = strrchr(path, '/')) == NULL) + q = path; + else if (*(q + 1) != '\0') + q++; } } else if (is_var(p, "$z")) { q = obj->Zone; @@ -321,7 +342,7 @@ no_volname: /* simple basename */ /* stuff up to next $ */ src = p + 2; p = strchr(src, '$'); - len = p ? MIN(p - src, destlen) : destlen; + len = p ? MIN((size_t)(p - src), destlen) : destlen; if (len > 0) { strncpy(dest, src, len); dest += len; @@ -384,7 +405,7 @@ static void volset(struct vol_option *options, struct vol_option *save, } else if (optionok(tmp, "codepage:", val)) { LOG (log_error, logtype_afpd, "The old codepage system has been removed. Please make sure to read the documentation !!!!"); /* Make sure we don't screw anything */ - exit (-1); + exit (EXITERR_CONF); } else if (optionok(tmp, "volcharset:", val)) { setoption(options, save, VOLOPT_ENCODING, val); } else if (optionok(tmp, "maccharset:", val)) { @@ -408,6 +429,8 @@ static void volset(struct vol_option *options, struct vol_option *save, #if AD_VERSION == AD_VERSION2 else if (strcasecmp(val + 1, "v2") == 0) options[VOLOPT_ADOUBLE].i_value = AD_VERSION2; + else if (strcasecmp(val + 1, "osx") == 0) + options[VOLOPT_ADOUBLE].i_value = AD_VERSION2_OSX; #endif } else if (optionok(tmp, "options:", val)) { char *p; @@ -419,7 +442,7 @@ static void volset(struct vol_option *options, struct vol_option *save, if (strcasecmp(p, "prodos") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_A2VOL; else if (strcasecmp(p, "mswindows") == 0) { - options[VOLOPT_FLAGS].i_value |= AFPVOL_MSWINDOWS; + options[VOLOPT_FLAGS].i_value |= AFPVOL_MSWINDOWS | AFPVOL_USEDOTS; } else if (strcasecmp(p, "crlf") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_CRLF; else if (strcasecmp(p, "noadouble") == 0) @@ -430,6 +453,8 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_FLAGS].i_value |= AFPVOL_NOHEX; else if (strcasecmp(p, "usedots") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS; + else if (strcasecmp(p, "invisibledots") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_USEDOTS | AFPVOL_INV_DOTS; else if (strcasecmp(p, "limitsize") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_LIMITSIZE; /* support for either "dropbox" or "dropkludge" */ @@ -447,6 +472,12 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_ROOTPREEXEC].i_value = 1; else if (strcasecmp(p, "upriv") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV; + else if (strcasecmp(p, "nodev") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_NODEV; + else if (strcasecmp(p, "illegalseq") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ; + else if (strcasecmp(p, "cachecnid") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE; p = strtok(NULL, ","); } @@ -455,7 +486,13 @@ static void volset(struct vol_option *options, struct vol_option *save, setoption(options, save, VOLOPT_DBPATH, val); } else if (optionok(tmp, "umask:", val)) { - options[VOLOPT_UMASK].i_value = (int)strtol(val, (char **)NULL, 8); + options[VOLOPT_UMASK].i_value = (int)strtol(val +1, NULL, 8); + } else if (optionok(tmp, "perm:", val)) { + options[VOLOPT_DFLTPERM].i_value = (int)strtol(val+1, NULL, 8); + } else if (optionok(tmp, "dperm:", val)) { + options[VOLOPT_DPERM].i_value = (int)strtol(val+1, NULL, 8); + } else if (optionok(tmp, "fperm:", val)) { + options[VOLOPT_FPERM].i_value = (int)strtol(val+1, NULL, 8); } else if (optionok(tmp, "mapchars:",val)) { setoption(options, save, VOLOPT_MAPCHARS, val); @@ -502,6 +539,38 @@ static void showvol(const ucs2_t *name) } } +/* ----------------- + * FIXME should be define elsewhere +*/ +static int validupath_adouble(const struct vol *vol, const char *name) +{ + return (vol->v_flags & AFPVOL_USEDOTS) ? + strcasecmp(name,".AppleDB") && + strcasecmp(name,".AppleDouble") && + strcasecmp(name,".AppleDesktop") && + strcasecmp(name,".Parent") + : name[0] != '.'; +} + +/* ----------------- */ +static int validupath_osx(const struct vol *vol _U_, const char *name) +{ + return strncasecmp(name,".Apple", 6) && strncasecmp(name,"._", 2); +} + +/* ---------------- */ +static void initvoladouble(struct vol *vol) +{ + if (vol->v_adouble == AD_VERSION2_OSX) { + vol->validupath = validupath_osx; + vol->ad_path = ad_path_osx; + } + else { + vol->validupath = validupath_adouble; + vol->ad_path = ad_path; + } +} + /* ------------------------------- */ static int creatvol(AFPObj *obj, struct passwd *pwd, char *path, char *name, @@ -579,6 +648,16 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, /* shift in some flags */ volume->v_flags = options[VOLOPT_FLAGS].i_value; + volume->v_ad_options = 0; + if ((volume->v_flags & AFPVOL_NODEV)) + volume->v_ad_options |= ADVOL_NODEV; + if ((volume->v_flags & AFPVOL_CACHE)) + volume->v_ad_options |= ADVOL_CACHE; + if ((volume->v_flags & AFPVOL_UNIX_PRIV)) + volume->v_ad_options |= ADVOL_UNIXPRIV; + if ((volume->v_flags & AFPVOL_INV_DOTS)) + volume->v_ad_options |= ADVOL_INVDOTS; + if (options[VOLOPT_PASSWORD].c_value) volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value); @@ -592,7 +671,7 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, volume->v_maccodepage = strdup(options[VOLOPT_MACCHARSET].c_value); if (options[VOLOPT_DBPATH].c_value) - volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_DBPATH].c_value, pwd, path); + volume->v_dbpath = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_DBPATH].c_value, pwd, path, name); if (options[VOLOPT_CNIDSCHEME].c_value) volume->v_cnidscheme = strdup(options[VOLOPT_CNIDSCHEME].c_value); @@ -600,6 +679,11 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, if (options[VOLOPT_UMASK].i_value) volume->v_umask = (mode_t)options[VOLOPT_UMASK].i_value; + if (options[VOLOPT_DPERM].i_value) + + if (options[VOLOPT_DFLTPERM].i_value) + volume->v_perm = (mode_t)options[VOLOPT_DFLTPERM].i_value; + if (options[VOLOPT_ADOUBLE].i_value) volume->v_adouble = options[VOLOPT_ADOUBLE].i_value; else @@ -619,21 +703,24 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, #endif if (!user) { if (options[VOLOPT_PREEXEC].c_value) - volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path); + volume->v_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_PREEXEC].c_value, pwd, path, name); volume->v_preexec_close = options[VOLOPT_PREEXEC].i_value; if (options[VOLOPT_POSTEXEC].c_value) - volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path); + volume->v_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_POSTEXEC].c_value, pwd, path, name); if (options[VOLOPT_ROOTPREEXEC].c_value) - volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path); + volume->v_root_preexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPREEXEC].c_value, pwd, path, name); volume->v_root_preexec_close = options[VOLOPT_ROOTPREEXEC].i_value; if (options[VOLOPT_ROOTPOSTEXEC].c_value) - volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path); + volume->v_root_postexec = volxlate(obj, NULL, MAXPATHLEN, options[VOLOPT_ROOTPOSTEXEC].c_value, pwd, path, name); } } + volume->v_dperm |= volume->v_perm; + volume->v_fperm |= volume->v_perm; + initvoladouble(volume); volume->v_next = Volumes; Volumes = volume; return 0; @@ -649,7 +736,7 @@ FILE *fp; int c; p = buf; - while ((EOF != ( c = getc( fp )) ) && ( size > 0 )) { + while ((EOF != ( c = getc( fp )) ) && ( size > 1 )) { if ( c == '\n' || c == '\r' ) { *p++ = '\n'; break; @@ -700,7 +787,7 @@ const char *name; if (!args) return -1; - strncpy(buf, args, sizeof(buf)); + strlcpy(buf, args, sizeof(buf)); if ((p = strtok(buf, ",")) == NULL) /* nothing, return okay */ return -1; @@ -788,7 +875,12 @@ static void sortextmap( void) } if (Extmap_cnt) { qsort(Extmap, Extmap_cnt, sizeof(struct extmap), extmap_cmp); - Defextmap = Extmap; + if (*Extmap->em_ext == 0) { + /* the first line is really "." the default entry, + * we remove the leading '.' in setextmap + */ + Defextmap = Extmap; + } } } @@ -930,7 +1022,7 @@ struct passwd *pwent; strcpy(tmp, path); if (!pwent) pwent = getpwnam(obj->username); - volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL); + volxlate(obj, path, sizeof(path) - 1, tmp, pwent, NULL, NULL); /* this is sort of braindead. basically, i want to be * able to specify things in any order, but i don't want to @@ -980,7 +1072,7 @@ struct passwd *pwent; options[VOLOPT_FLAGS].i_value |= AFPVOL_RO; /* do variable substitution for volname */ - volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path); + volxlate(obj, tmp, sizeof(tmp) - 1, volname, pwent, path, NULL); creatvol(obj, pwent, path, tmp, options, p2 != NULL); } volfree(options, save_options); @@ -1172,7 +1264,7 @@ int *buflen; * For MacOS8.x support we need to create the * .Parent file here if it doesn't exist. */ - ad_init(&ad, vol->v_adouble); + ad_init(&ad, vol->v_adouble, vol->v_ad_options); if ( ad_open( vol->v_path, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR, O_RDWR | O_CREAT, 0666, &ad) < 0 ) { @@ -1185,10 +1277,11 @@ int *buflen; slash++; else slash = vol->v_path; - - ad_setentrylen( &ad, ADEID_NAME, strlen( slash )); - memcpy(ad_entry( &ad, ADEID_NAME ), slash, + if (ad_getentryoff(&ad, ADEID_NAME)) { + ad_setentrylen( &ad, ADEID_NAME, strlen( slash )); + memcpy(ad_entry( &ad, ADEID_NAME ), slash, ad_getentrylen( &ad, ADEID_NAME )); + } vol_setdate(vol->v_vid, &ad, st->st_mtime); ad_flush(&ad, ADFLAGS_HF); } @@ -1334,7 +1427,8 @@ int *buflen; if ( nameoff ) { ashort = htons( data - buf ); memcpy(nameoff, &ashort, sizeof( ashort )); - aint = ucs2_to_charset( (utf8_encoding()?CH_UTF8_MAC:vol->v_maccharset), vol->v_name, data+1, 255); + /* name is always in mac charset, FIXME mangle if length > 27 char */ + aint = ucs2_to_charset( vol->v_maccharset, vol->v_name, data+1, 255); if ( aint <= 0 ) { *buflen = 0; return AFPERR_MISC; @@ -1351,7 +1445,7 @@ int *buflen; } /* ------------------------- */ -int static stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen) +static int stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen) { struct stat st; int buflen, ret; @@ -1360,9 +1454,11 @@ int static stat_vol(u_int16_t bitmap, struct vol *vol, char *rbuf, int *rbuflen) *rbuflen = 0; return( AFPERR_PARAM ); } + /* save the volume device number */ + vol->v_dev = st.st_dev; buflen = *rbuflen - sizeof( bitmap ); - if (( ret = getvolparams(bitmap, vol, &st, + if (( ret = getvolparams( bitmap, vol, &st, rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) { *rbuflen = 0; return( ret ); @@ -1433,33 +1529,45 @@ void load_volumes(AFPObj *obj) /* ------------------------------- */ int afp_getsrvrparms(obj, ibuf, ibuflen, rbuf, rbuflen ) AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +char *ibuf _U_, *rbuf; +int ibuflen _U_, *rbuflen; { struct timeval tv; struct stat st; struct vol *volume; char *data; char *namebuf; - int vcnt, len; + int vcnt; + size_t len; load_volumes(obj); data = rbuf + 5; for ( vcnt = 0, volume = Volumes; volume; volume = volume->v_next ) { if (!(volume->v_flags & AFPVOL_NOSTAT)) { + struct maccess ma; + if ( stat( volume->v_path, &st ) < 0 ) { - LOG(log_info, logtype_afpd, "afp_getsrvrparms: stat %s: %s", + LOG(log_info, logtype_afpd, "afp_getsrvrparms(%s): stat: %s", volume->v_path, strerror(errno) ); continue; /* can't access directory */ } if (!S_ISDIR(st.st_mode)) { continue; /* not a dir */ } + accessmode(volume->v_path, &ma, NULL, &st); + if ((ma.ma_user & (AR_UREAD | AR_USEARCH)) != (AR_UREAD | AR_USEARCH)) { + continue; /* no r-x access */ + } } if (volume->v_hide) { continue; /* config file changed but the volume was mounted */ } + len = ucs2_to_charset_allocate((utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), + &namebuf, volume->v_name); + if (len == (size_t)-1) + continue; + /* set password bit if there's a volume password */ *data = (volume->v_password) ? AFPSRVR_PASSWD : 0; @@ -1471,11 +1579,6 @@ int ibuflen, *rbuflen; off.. */ *data |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0; *data++ |= 0; /* UNIX PRIVS BIT ..., OSX doesn't seem to use it, so we don't either */ - - len = ucs2_to_charset_allocate((utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), - &namebuf, volume->v_name); - if (len <= 0) - continue; *data++ = len; memcpy(data, namebuf, len ); data += len; @@ -1486,7 +1589,7 @@ int ibuflen, *rbuflen; *rbuflen = data - rbuf; data = rbuf; if ( gettimeofday( &tv, 0 ) < 0 ) { - LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) ); + LOG(log_error, logtype_afpd, "afp_getsrvrparms(%s): gettimeofday: %s", volume->v_path, strerror(errno) ); *rbuflen = 0; return AFPERR_PARAM; } @@ -1503,7 +1606,7 @@ int ibuflen, *rbuflen; int afp_openvol(obj, ibuf, ibuflen, rbuf, rbuflen ) AFPObj *obj; char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int ibuflen _U_, *rbuflen; { struct stat st; char *volname; @@ -1513,6 +1616,7 @@ int ibuflen, *rbuflen; int len, ret; size_t namelen; u_int16_t bitmap; + char path[ MAXPATHLEN + 1]; char *vol_uname; char *vol_mname; @@ -1577,42 +1681,12 @@ int ibuflen, *rbuflen; volume->v_dir = volume->v_root = NULL; - /* FIXME unix name != mac name */ - - len = convert_string_allocate( CH_UCS2, (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), - volume->v_name, namelen, &vol_mname); - if ( !vol_mname || len <= 0) { - ret = AFPERR_MISC; - goto openvol_err; - } - - len = convert_string_allocate( CH_UCS2 , volume->v_volcharset, volume->v_name, namelen, &vol_uname); - - if ( !vol_uname || len <= 0) { - free(vol_mname); - ret = AFPERR_MISC; - goto openvol_err; - } - - if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) { - free(vol_mname); - free(vol_uname); - LOG(log_error, logtype_afpd, "afp_openvol: malloc: %s", strerror(errno) ); - ret = AFPERR_MISC; - goto openvol_err; - } - free(vol_mname); - free(vol_uname); - - dir->d_did = DIRDID_ROOT; - dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */ - volume->v_dir = volume->v_root = dir; volume->v_flags |= AFPVOL_OPEN; volume->v_cdb = NULL; if (volume->v_root_preexec) { if ((ret = afprun(1, volume->v_root_preexec, NULL)) && volume->v_root_preexec_close) { - LOG(log_error, logtype_afpd, "afp_openvol: root preexec : %d", ret ); + LOG(log_error, logtype_afpd, "afp_openvol(%s): root preexec : %d", volume->v_path, ret ); ret = AFPERR_MISC; goto openvol_err; } @@ -1624,7 +1698,7 @@ int ibuflen, *rbuflen; if (volume->v_preexec) { if ((ret = afprun(0, volume->v_preexec, NULL)) && volume->v_preexec_close) { - LOG(log_error, logtype_afpd, "afp_openvol: preexec : %d", ret ); + LOG(log_error, logtype_afpd, "afp_openvol(%s): preexec : %d", volume->v_path, ret ); ret = AFPERR_MISC; goto openvol_err; } @@ -1639,6 +1713,38 @@ int ibuflen, *rbuflen; ret = AFPERR_PARAM; goto openvol_err; } + + len = convert_string_allocate( CH_UCS2, (utf8_encoding()?CH_UTF8_MAC:obj->options.maccharset), + volume->v_name, namelen, &vol_mname); + if ( !vol_mname || len <= 0) { + ret = AFPERR_MISC; + goto openvol_err; + } + + if ( NULL == getcwd(path, MAXPATHLEN)) { + /* shouldn't be fatal but it will fail later */ + LOG(log_error, logtype_afpd, "afp_openvol(%s): volume pathlen too long", volume->v_path); + ret = AFPERR_MISC; + goto openvol_err; + } + + if ((vol_uname = strrchr(path, '/')) == NULL) + vol_uname = path; + else if (*(vol_uname + 1) != '\0') + vol_uname++; + + if ((dir = dirnew(vol_mname, vol_uname) ) == NULL) { + free(vol_mname); + LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) ); + ret = AFPERR_MISC; + goto openvol_err; + } + free(vol_mname); + + dir->d_did = DIRDID_ROOT; + dir->d_color = DIRTREE_COLOR_BLACK; /* root node is black */ + volume->v_dir = volume->v_root = dir; + curdir = volume->v_dir; if (volume->v_cnidscheme == NULL) { volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME); @@ -1646,9 +1752,9 @@ int ibuflen, *rbuflen; volume->v_path); } if (volume->v_dbpath) - volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme); + volume->v_cdb = cnid_open (volume->v_dbpath, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV)); else - volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme); + volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, volume->v_cnidscheme, (volume->v_flags & AFPVOL_NODEV)); if (volume->v_cdb == NULL) { LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID or invalid CNID backend for %s: %s", volume->v_path, volume->v_cnidscheme); @@ -1689,7 +1795,10 @@ int ibuflen, *rbuflen; ret = stat_vol(bitmap, volume, rbuf, rbuflen); if (ret == AFP_OK) { - handle_special_folders( volume ); + if (!(volume->v_flags & AFPVOL_RO)) { + handle_special_folders( volume ); + savevoloptions( volume); + } /* * If you mount a volume twice, the second time the trash appears on @@ -1702,7 +1811,13 @@ int ibuflen, *rbuflen; if ((volume->v_cdb->flags & CNID_FLAG_PERSISTENT)) { /* FIXME find db time stamp */ - cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)); + if (cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) < 0) { + LOG (log_error, logtype_afpd, + "afp_openvol(%s): Fatal error: Unable to get stamp value from CNID backend", + volume->v_path); + ret = AFPERR_MISC; + goto openvol_err; + } } else { p = Trash; @@ -1753,7 +1868,7 @@ void close_all_vol(void) struct vol *ovol; curdir = NULL; for ( ovol = Volumes; ovol; ovol = ovol->v_next ) { - if ( ovol->v_flags & AFPVOL_OPEN ) { + if ( (ovol->v_flags & AFPVOL_OPEN) ) { ovol->v_flags &= ~AFPVOL_OPEN; closevol(ovol); } @@ -1762,9 +1877,9 @@ void close_all_vol(void) /* ------------------------- */ int afp_closevol(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen _U_, *rbuflen; { struct vol *vol, *ovol; u_int16_t vid; @@ -1778,7 +1893,7 @@ int ibuflen, *rbuflen; vol->v_flags &= ~AFPVOL_OPEN; for ( ovol = Volumes; ovol; ovol = ovol->v_next ) { - if ( ovol->v_flags & AFPVOL_OPEN ) { + if ( (ovol->v_flags & AFPVOL_OPEN) ) { break; } } @@ -1896,7 +2011,7 @@ struct vol *vol; * [RS] */ if ( gettimeofday( &tv, 0 ) < 0 ) { - LOG(log_error, logtype_afpd, "setvoltime: gettimeofday: %s", strerror(errno) ); + LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) ); return; } if( utime( vol->v_path, NULL ) < 0 ) { @@ -1908,20 +2023,18 @@ struct vol *vol; /* a little granularity */ if (vol->v_mtime < tv.tv_sec) { vol->v_mtime = tv.tv_sec; -#if 0 -/* if 0ed, we're sending too many */ + /* or finder doesn't update free space */ if (afp_version > 21 && obj->options.server_notif) { obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED); } -#endif } } /* ------------------------- */ int afp_getvolparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; +AFPObj *obj _U_; char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int ibuflen _U_, *rbuflen; { struct vol *vol; u_int16_t vid, bitmap; @@ -1942,9 +2055,9 @@ int ibuflen, *rbuflen; /* ------------------------- */ int afp_setvolparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +AFPObj *obj _U_; +char *ibuf, *rbuf _U_; +int ibuflen _U_, *rbuflen; { struct adouble ad; struct vol *vol; @@ -1964,14 +2077,14 @@ int ibuflen, *rbuflen; return( AFPERR_PARAM ); } - if (vol->v_flags & AFPVOL_RO) + if ((vol->v_flags & AFPVOL_RO)) return AFPERR_VLOCK; /* we can only set the backup date. */ if (bitmap != (1 << VOLPBIT_BDATE)) return AFPERR_BITMAP; - ad_init(&ad, vol->v_adouble); + ad_init(&ad, vol->v_adouble, vol->v_ad_options); if ( ad_open( vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR, 0666, &ad) < 0 ) { if (errno == EROFS) @@ -2021,7 +2134,7 @@ int wincheck(const struct vol *vol, const char *path) */ static int create_special_folder (const struct vol *vol, const struct _special_folder *folder) { - char *p; + char *p,*q,*r; struct adouble ad; u_int16_t attr; struct stat st; @@ -2031,17 +2144,34 @@ static int create_special_folder (const struct vol *vol, const struct _special_f p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2); if ( p == NULL) { LOG(log_error, logtype_afpd,"malloc failed"); - exit (-1); + exit (EXITERR_SYS); + } + + q=strdup(folder->name); + if ( q == NULL) { + LOG(log_error, logtype_afpd,"malloc failed"); + exit (EXITERR_SYS); } + strcpy(p, vol->v_path); strcat(p, "/"); - strcat(p, folder->name); + + r=q; + while (*r) { + if ((vol->v_casefold & AFPVOL_MTOUUPPER)) + *r=toupper(*r); + else if ((vol->v_casefold & AFPVOL_MTOULOWER)) + *r=tolower(*r); + r++; + } + strcat(p, q); if ( (ret = stat( p, &st )) < 0 ) { if (folder->precreate) { - if (ad_mkdir(p, folder->mode & ~vol->v_umask)) { - LOG(log_debug, logtype_afpd,"Creating '%s' failed", folder->name); + if (ad_mkdir(p, folder->mode)) { + LOG(log_debug, logtype_afpd,"Creating '%s' failed in %s: %s", p, vol->v_path, strerror(errno)); free(p); + free(q); return -1; } ret = 0; @@ -2050,26 +2180,37 @@ static int create_special_folder (const struct vol *vol, const struct _special_f if ( !ret && folder->hide) { /* Hide it */ - ad_init(&ad, vol->v_adouble); + ad_init(&ad, vol->v_adouble, vol->v_ad_options); if (ad_open( p, vol_noadouble(vol) | ADFLAGS_HF|ADFLAGS_DIR, O_RDWR|O_CREAT, 0666, &ad) < 0) { free (p); + free(q); return (-1); } if ((ad_get_HF_flags( &ad ) & O_CREAT) ) { - ad_setentrylen( &ad, ADEID_NAME, strlen(folder->name)); - memcpy(ad_entry( &ad, ADEID_NAME ), folder->name, - ad_getentrylen( &ad, ADEID_NAME )); + if (ad_getentryoff(&ad, ADEID_NAME)) { + ad_setentrylen( &ad, ADEID_NAME, strlen(folder->name)); + memcpy(ad_entry( &ad, ADEID_NAME ), folder->name, + ad_getentrylen( &ad, ADEID_NAME )); + } } ad_getattr(&ad, &attr); attr |= htons( ntohs( attr ) | ATTRBIT_INVISIBLE ); ad_setattr(&ad, attr); - + + /* do the same with the finder info */ + if (ad_entry(&ad, ADEID_FINDERI)) { + memcpy(&attr, ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, sizeof(attr)); + attr |= htons(FINDERINFO_INVISIBLE); + memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr)); + } + ad_flush( &ad, ADFLAGS_HF ); ad_close( &ad, ADFLAGS_HF ); } free(p); + free(q); return 0; } @@ -2077,7 +2218,7 @@ static void handle_special_folders (const struct vol * vol) { const _special_folder *p = &special_folders[0]; - if (vol->v_flags & AFPVOL_RO) + if ((vol->v_flags & AFPVOL_RO)) return; for (; p->name != NULL; p++) { @@ -2085,3 +2226,115 @@ static void handle_special_folders (const struct vol * vol) } } +/* + * Save the volume options to a file, used by + * shell utilities. + * Writing the file everytime a volume is opened is + * unnecessary, but it shouldn't hurt much. + */ +static int savevoloptions (const struct vol *vol) +{ + char buf[16348]; + char item[MAXPATHLEN]; + int fd; + int ret = 0; + struct flock lock; + const _vol_opt_name *op = &vol_opt_names[0]; + const _vol_opt_name *cf = &vol_opt_casefold[0]; + + strlcpy (item, vol->v_path, sizeof(item)); + strlcat (item, "/.AppleDesktop/", sizeof(item)); + strlcat (item, VOLINFOFILE, sizeof(item)); + + if ((fd = open( item, O_RDWR | O_CREAT , 0666)) <0 ) { + LOG(log_debug, logtype_afpd,"Error opening %s: %s", item, strerror(errno)); + return (-1); + } + + /* try to get a lock */ + lock.l_start = 0; + lock.l_whence = SEEK_SET; + lock.l_len = 0; + lock.l_type = F_WRLCK; + + if (fcntl(fd, F_SETLK, &lock) < 0) { + if (errno == EACCES || errno == EAGAIN) { + /* ignore, other process already writing the file */ + return 0; + } else { + LOG(log_error, logtype_cnid, "savevoloptions: cannot get lock: %s", strerror(errno)); + return (-1); + } + } + + /* write volume options */ + snprintf(buf, sizeof(buf), "MAC_CHARSET:%s\n", vol->v_maccodepage); + snprintf(item, sizeof(item), "VOL_CHARSET:%s\n", vol->v_volcodepage); + strlcat(buf, item, sizeof(buf)); + + switch (vol->v_adouble) { + case AD_VERSION1: + strlcat(buf, "ADOUBLE_VER:v1\n", sizeof(buf)); + break; + case AD_VERSION2: + strlcat(buf, "ADOUBLE_VER:v2\n", sizeof(buf)); + break; + case AD_VERSION2_OSX: + strlcat(buf, "ADOUBLE_VER:osx\n", sizeof(buf)); + break; + } + + strlcat(buf, "CNIDBACKEND:", sizeof(buf)); + strlcat(buf, vol->v_cnidscheme, sizeof(buf)); + strlcat(buf, "\n", sizeof(buf)); + + strlcat(buf, "CNIDDBDHOST:", sizeof(buf)); + strlcat(buf, Cnid_srv, sizeof(buf)); + strlcat(buf, "\n", sizeof(buf)); + + snprintf(item, sizeof(item), "CNIDDBDPORT:%u\n", Cnid_port); + strlcat(buf, item, sizeof(buf)); + + strcpy(item, "CNID_DBPATH:"); + if (vol->v_dbpath) + strlcat(item, vol->v_dbpath, sizeof(item)); + else + strlcat(item, vol->v_path, sizeof(item)); + strlcat(item, "\n", sizeof(item)); + strlcat(buf, item, sizeof(buf)); + + /* volume flags */ + strcpy(item, "VOLUME_OPTS:"); + for (;op->name; op++) { + if ( (vol->v_flags & op->option) ) { + strlcat(item, op->name, sizeof(item)); + strlcat(item, " ", sizeof(item)); + } + } + strlcat(item, "\n", sizeof(item)); + strlcat(buf, item, sizeof(buf)); + + /* casefold flags */ + strcpy(item, "VOLCASEFOLD:"); + for (;cf->name; cf++) { + if ( (vol->v_casefold & cf->option) ) { + strlcat(item, cf->name, sizeof(item)); + strlcat(item, " ", sizeof(item)); + } + } + strlcat(item, "\n", sizeof(item)); + strlcat(buf, item, sizeof(buf)); + + if (strlen(buf) >= sizeof(buf)-1) + LOG(log_debug, logtype_afpd,"Error writing .volinfo file: buffer too small, %s", buf); + + + if (write( fd, buf, strlen(buf)) < 0 || ftruncate(fd, strlen(buf)) < 0 ) { + LOG(log_debug, logtype_afpd,"Error writing .volinfo file: %s", strerror(errno)); + } + + lock.l_type = F_UNLCK; + fcntl(fd, F_SETLK, &lock); + close (fd); + return ret; +}