X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Fvolume.c;h=7bdff75dff53ecf87007a9b001a45c87bae944de;hp=a8b0754dd0cd799eb7c9a8c914ee3f6fa9b381e4;hb=5eb3b5ac51c8221009041928a5a08c101d2be743;hpb=8a1fcacef082abe5bdb60421b3129d7cd39f6b76 diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index a8b0754d..7bdff75d 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -40,6 +39,7 @@ #include #include #include +#include #ifdef CNID_DB #include @@ -58,63 +58,6 @@ extern int afprun(int root, char *cmd, int *outfd); -typedef struct _special_folder { - const char *name; - int precreate; - mode_t mode; - int hide; -} _special_folder; - -static const _special_folder special_folders[] = { - {".AppleDesktop", 1, 0777, 0}, - {NULL, 0, 0, 0}}; - -/* Forward declarations */ -static void handle_special_folders (const struct vol *); - -static void showvol(const ucs2_t *name) -{ - struct vol *volume = getvolumes(); - - for ( ; volume; volume = volume->v_next ) { - if (volume->v_hide && !strcasecmp_w( volume->v_name, name ) ) { - volume->v_hide = 0; - return; - } - } -} - -static void closevol(struct vol *vol) -{ - if (!vol) - return; - - vol->v_flags &= ~AFPVOL_OPEN; - - of_closevol(vol); - - dir_free( vol->v_root ); - vol->v_root = NULL; - if (vol->v_cdb != NULL) { - cnid_close(vol->v_cdb); - vol->v_cdb = NULL; - } - - if (vol->v_postexec) { - afprun(0, vol->v_postexec, NULL); - } - if (vol->v_root_postexec) { - afprun(1, vol->v_root_postexec, NULL); - } - - if (vol->v_deleted) { - showvol(vol->v_name); - volume_free(vol); - volume_unlink(vol); - free(vol); - } -} - /*! * Read band-size info from Info.plist XML file of an TM sparsebundle * @@ -210,7 +153,6 @@ static int get_tm_used(struct vol * restrict vol) DIR *dir = NULL; const struct dirent *entry; const char *p; - struct stat st; long int links; time_t now = time(NULL); @@ -235,13 +177,18 @@ static int get_tm_used(struct vol * restrict vol) EC_NULL_LOG( infoplist = bformat("%s/%s/%s", vol->v_path, entry->d_name, "Info.plist") ); - if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) + if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) { + bdestroy(infoplist); continue; + } EC_NULL_LOG( bandsdir = bformat("%s/%s/%s/", vol->v_path, entry->d_name, "bands") ); - if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) + if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) { + bdestroy(infoplist); + bdestroy(bandsdir); continue; + } used += (links - 1) * bandsize; LOG(log_debug, logtype_afpd, "getused(\"%s\"): bands: %" PRIu64 " bytes", @@ -270,14 +217,13 @@ static int getvolspace(const AFPObj *obj, struct vol *vol, { int spaceflag, rc; uint32_t maxsize; - VolSpace used; #ifndef NO_QUOTA_SUPPORT VolSpace qfree, qtotal; #endif spaceflag = AFPVOL_GVSMASK & vol->v_flags; /* report up to 2GB if afp version is < 2.2 (4GB if not) */ - maxsize = (afp_version < 22) ? 0x7fffffffL : 0xffffffffL; + maxsize = (obj->afp_version < 22) ? 0x7fffffffL : 0xffffffffL; #ifdef AFS if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_AFSGVS ) { @@ -322,22 +268,6 @@ getvolspace_done: return( AFP_OK ); } -#define FCE_TM_DELTA 10 /* send notification every 10 seconds */ -void vol_fce_tm_event(void) -{ - static time_t last; - time_t now = time(NULL); - struct vol *vol = getvolumes(); - - if ((last + FCE_TM_DELTA) < now) { - last = now; - for ( ; vol; vol = vol->v_next ) { - if (vol->v_flags & AFPVOL_TM) - (void)fce_register_tm_size(vol->v_path, vol->v_tm_used + vol->v_appended); - } - } -} - /* ----------------------- * set volume creation date * avoid duplicate, well at least it tries @@ -379,7 +309,7 @@ static int getvolparams(const AFPObj *obj, uint16_t bitmap, struct vol *vol, str * .Parent file here if it doesn't exist. */ /* Convert adouble:v2 to adouble:ea on the fly */ - (void)ad_convert(vol->v_path, st, vol); + (void)ad_convert(vol->v_path, st, vol, NULL); ad_init(&ad, vol); if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) { @@ -438,12 +368,12 @@ static int getvolparams(const AFPObj *obj, uint16_t bitmap, struct vol *vol, str ashort |= VOLPBIT_ATTR_RO; } /* prior 2.1 only VOLPBIT_ATTR_RO is defined */ - if (afp_version > 20) { - if (vol->v_cdb != NULL && (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) + if (obj->afp_version > 20) { + if (vol->v_cdb != NULL && (vol->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT)) ashort |= VOLPBIT_ATTR_FILEID; ashort |= VOLPBIT_ATTR_CATSEARCH; - if (afp_version >= 30) { + if (obj->afp_version >= 30) { ashort |= VOLPBIT_ATTR_UTF8; if (vol->v_flags & AFPVOL_UNIX_PRIV) ashort |= VOLPBIT_ATTR_UNIXPRIV; @@ -451,7 +381,7 @@ static int getvolparams(const AFPObj *obj, uint16_t bitmap, struct vol *vol, str ashort |= VOLPBIT_ATTR_TM; if (vol->v_flags & AFPVOL_NONETIDS) ashort |= VOLPBIT_ATTR_NONETIDS; - if (afp_version >= 32) { + if (obj->afp_version >= 32) { if (vol->v_vfs_ea) ashort |= VOLPBIT_ATTR_EXT_ATTRS; if (vol->v_flags & AFPVOL_ACLS) @@ -600,11 +530,12 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf char *namebuf; int vcnt; size_t len; + uint32_t aint; - load_volumes(obj, of_closevol); + load_volumes(obj, lv_none); data = rbuf + 5; - for ( vcnt = 0, volume = getvolumes(); volume; volume = volume->v_next ) { + for ( vcnt = 0, volume = getvolumes(); volume && vcnt < 255; volume = volume->v_next ) { if (!(volume->v_flags & AFPVOL_NOSTAT)) { struct maccess ma; @@ -621,11 +552,8 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf continue; /* no r-x access */ } } - if (volume->v_hide) { - continue; /* config file changed but the volume was mounted */ - } - if (utf8_encoding()) { + if (utf8_encoding(obj)) { len = ucs2_to_charset_allocate(CH_UTF8_MAC, &namebuf, volume->v_u8mname); } else { len = ucs2_to_charset_allocate(obj->options.maccharset, &namebuf, volume->v_macname); @@ -634,6 +562,14 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf if (len == (size_t)-1) continue; + /* + * There seems to be an undocumented limit on how big our reply can get + * before the client chokes and closes the connection. + * Testing with 10.8.4 found the limit at ~4600 bytes. Go figure. + */ + if (((data + len + 3) - rbuf) > 4600) + break; + /* set password bit if there's a volume password */ *data = (volume->v_password) ? AFPSRVR_PASSWD : 0; @@ -648,12 +584,13 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf *rbuflen = data - rbuf; data = rbuf; if ( gettimeofday( &tv, NULL ) < 0 ) { - LOG(log_error, logtype_afpd, "afp_getsrvrparms(%s): gettimeofday: %s", volume->v_path, strerror(errno) ); + LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) ); *rbuflen = 0; return AFPERR_PARAM; } - tv.tv_sec = AD_DATE_FROM_UNIX(tv.tv_sec); - memcpy(data, &tv.tv_sec, sizeof( uint32_t)); + + aint = AD_DATE_FROM_UNIX(tv.tv_sec); + memcpy(data, &aint, sizeof( uint32_t)); data += sizeof( uint32_t); *data = vcnt; return( AFP_OK ); @@ -702,22 +639,7 @@ static int volume_openDB(const AFPObj *obj, struct vol *volume) flags |= CNID_FLAG_NODEV; } - if (volume->v_cnidscheme == NULL) { - volume->v_cnidscheme = strdup(DEFAULT_CNID_SCHEME); - LOG(log_info, logtype_afpd, "Volume %s use CNID scheme %s.", - volume->v_path, volume->v_cnidscheme); - } - - LOG(log_info, logtype_afpd, "CNID server: %s:%s", - volume->v_cnidserver ? volume->v_cnidserver : obj->options.Cnid_srv, - volume->v_cnidport ? volume->v_cnidport : obj->options.Cnid_port); - - volume->v_cdb = cnid_open(volume->v_path, - volume->v_umask, - volume->v_cnidscheme, - flags, - volume->v_cnidserver ? volume->v_cnidserver : obj->options.Cnid_srv, - volume->v_cnidport ? volume->v_cnidport : obj->options.Cnid_port); + volume->v_cdb = cnid_open(volume, volume->v_cnidscheme, flags); if ( ! volume->v_cdb && ! (flags & CNID_FLAG_MEMORY)) { /* The first attempt failed and it wasn't yet an attempt to open in-memory */ @@ -726,7 +648,7 @@ static int volume_openDB(const AFPObj *obj, struct vol *volume) LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.", volume->v_path); flags |= CNID_FLAG_MEMORY; - volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL); + volume->v_cdb = cnid_open(volume, "tdb", flags); #ifdef SERVERTEXT /* kill ourself with SIGUSR2 aka msg pending */ if (volume->v_cdb) { @@ -741,6 +663,31 @@ static int volume_openDB(const AFPObj *obj, struct vol *volume) return (!volume->v_cdb)?-1:0; } +/* + * Send list of open volumes to afpd master via IPC + */ +static void server_ipc_volumes(AFPObj *obj) +{ + struct vol *volume, *vols; + volume = vols = getvolumes(); + bstring openvolnames = bfromcstr(""); + bool firstvol = true; + + while (volume) { + if (volume->v_flags & AFPVOL_OPEN) { + if (!firstvol) + bcatcstr(openvolnames, ", "); + else + firstvol = false; + bcatcstr(openvolnames, volume->v_localname); + } + volume = volume->v_next; + } + + ipc_child_write(obj->ipc_fd, IPC_VOLUMES, blength(openvolnames), bdata(openvolnames)); + bdestroy(openvolnames); +} + /* ------------------------- * we are the user here */ @@ -748,16 +695,14 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t { struct stat st; char *volname; - char *p; struct vol *volume; struct dir *dir; int len, ret; size_t namelen; uint16_t bitmap; - char path[ MAXPATHLEN + 1]; char *vol_uname; - char *vol_mname; + char *vol_mname = NULL; char *volname_tmp; ibuf += 2; @@ -776,7 +721,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t if ((volname_tmp = strchr(volname,'+')) != NULL) volname = volname_tmp+1; - if (utf8_encoding()) { + if (utf8_encoding(obj)) { namelen = convert_string(CH_UTF8_MAC, CH_UCS2, ibuf, len, volname, sizeof(obj->oldtmp)); } else { namelen = convert_string(obj->options.maccharset, CH_UCS2, ibuf, len, volname, sizeof(obj->oldtmp)); @@ -790,7 +735,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t if ((len + 1) & 1) /* pad to an even boundary */ ibuf++; - load_volumes(obj, of_closevol); + load_volumes(obj, lv_none); for ( volume = getvolumes(); volume; volume = volume->v_next ) { if ( strcasecmp_w( (ucs2_t*) volname, volume->v_name ) == 0 ) { @@ -834,33 +779,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t return AFPERR_PARAM; } - 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); - return AFPERR_MISC; - } - - /* Normalize volume path */ -#ifdef REALPATH_TAKES_NULL - if ((volume->v_path = realpath(path, NULL)) == NULL) - return AFPERR_MISC; -#else - if ((volume->v_path = malloc(MAXPATHLEN+1)) == NULL) - return AFPERR_MISC; - if (realpath(path, volume->v_path) == NULL) { - free(volume->v_path); - return AFPERR_MISC; - } - /* Safe some memory */ - char *tmp; - if ((tmp = strdup(volume->v_path)) == NULL) { - free(volume->v_path); - return AFPERR_MISC; - } - free(volume->v_path); - volume->v_path = tmp; -#endif - if (volume_codepage(obj, volume) < 0) { ret = AFPERR_MISC; goto openvol_err; @@ -869,7 +787,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t /* initialize volume variables * FIXME file size */ - if (utf8_encoding()) { + if (utf8_encoding(obj)) { volume->max_filename = UTF8FILELEN_EARLY; } else { @@ -879,7 +797,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t volume->v_flags |= AFPVOL_OPEN; volume->v_cdb = NULL; - if (utf8_encoding()) { + if (utf8_encoding(obj)) { len = convert_string_allocate(CH_UCS2, CH_UTF8_MAC, volume->v_u8mname, namelen, &vol_mname); } else { len = convert_string_allocate(CH_UCS2, obj->options.maccharset, volume->v_macname, namelen, &vol_mname); @@ -889,9 +807,9 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t goto openvol_err; } - if ((vol_uname = strrchr(path, '/')) == NULL) - vol_uname = path; - else if (*(vol_uname + 1) != '\0') + if ((vol_uname = strrchr(volume->v_path, '/')) == NULL) + vol_uname = volume->v_path; + else if (vol_uname[1] != '\0') vol_uname++; if ((dir = dir_new(vol_mname, @@ -907,7 +825,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t ret = AFPERR_MISC; goto openvol_err; } - free(vol_mname); volume->v_root = dir; curdir = dir; @@ -921,12 +838,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t ret = stat_vol(obj, bitmap, volume, rbuf, rbuflen); if (ret == AFP_OK) { - handle_special_folders(volume); - savevolinfo(volume, - volume->v_cnidserver ? volume->v_cnidserver : obj->options.Cnid_srv, - volume->v_cnidport ? volume->v_cnidport : obj->options.Cnid_port); - - /* * If you mount a volume twice, the second time the trash appears on * the desk-top. That's because the Mac remembers the DID for the @@ -935,7 +846,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t * fixing the trash at DID 17. * FIXME (RL): should it be done inside a CNID backend ? (always returning Trash DID when asked) ? */ - if ((volume->v_cdb->flags & CNID_FLAG_PERSISTENT)) { + if ((volume->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT)) { /* FIXME find db time stamp */ if (cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) < 0) { @@ -946,6 +857,13 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t goto openvol_err; } } + + const char *msg; + if ((msg = atalk_iniparser_getstring(obj->iniconfig, volume->v_configname, "login message", NULL)) != NULL) + setmessage(msg); + + free(vol_mname); + server_ipc_volumes(obj); return( AFP_OK ); } @@ -960,25 +878,50 @@ openvol_err: cnid_close(volume->v_cdb); volume->v_cdb = NULL; } + free(vol_mname); *rbuflen = 0; return ret; } +void closevol(const AFPObj *obj, struct vol *vol) +{ + if (!vol) + return; + + vol->v_flags &= ~AFPVOL_OPEN; + + of_closevol(obj, vol); + + dir_free( vol->v_root ); + vol->v_root = NULL; + if (vol->v_cdb != NULL) { + cnid_close(vol->v_cdb); + vol->v_cdb = NULL; + } + + if (vol->v_postexec) { + afprun(0, vol->v_postexec, NULL); + } + if (vol->v_root_postexec) { + afprun(1, vol->v_root_postexec, NULL); + } +} + /* ------------------------- */ -void close_all_vol(void) +void close_all_vol(const AFPObj *obj) { struct vol *ovol; curdir = NULL; for ( ovol = getvolumes(); ovol; ovol = ovol->v_next ) { if ( (ovol->v_flags & AFPVOL_OPEN) ) { ovol->v_flags &= ~AFPVOL_OPEN; - closevol(ovol); + closevol(obj, ovol); } } } /* ------------------------- */ -int afp_closevol(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) +int afp_closevol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { struct vol *vol; uint16_t vid; @@ -991,7 +934,9 @@ int afp_closevol(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ } (void)chdir("/"); - closevol(vol); + curdir = NULL; + closevol(obj, vol); + server_ipc_volumes(obj); return( AFP_OK ); } @@ -1015,7 +960,7 @@ int pollvoltime(AFPObj *obj) struct timeval tv; struct stat st; - if (!(afp_version > 21 && obj->options.flags & OPTION_SERVERNOTIF)) + if (!(obj->afp_version > 21 && obj->options.flags & OPTION_SERVERNOTIF)) return 0; if ( gettimeofday( &tv, NULL ) < 0 ) @@ -1055,7 +1000,7 @@ void setvoltime(AFPObj *obj, struct vol *vol) /* or finder doesn't update free space * AFP 3.2 and above clients seem to be ok without so many notification */ - if (afp_version < 32 && obj->options.flags & OPTION_SERVERNOTIF) { + if (obj->afp_version < 32 && obj->options.flags & OPTION_SERVERNOTIF) { obj->attention(obj->dsi, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED); } } @@ -1123,97 +1068,3 @@ int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf ad_close(&ad, ADFLAGS_HF); return( AFP_OK ); } - -/* - * precreate a folder - * this is only intended for folders in the volume root - * It will *not* work if the folder name contains extended characters - */ -static int create_special_folder (const struct vol *vol, const struct _special_folder *folder) -{ - char *p,*q,*r; - struct adouble ad; - uint16_t attr; - struct stat st; - int ret; - - - p = (char *) malloc ( strlen(vol->v_path)+strlen(folder->name)+2); - if ( p == NULL) { - LOG(log_error, logtype_afpd,"malloc failed"); - 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, "/"); - - 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)) { - 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; - } - } - - if ( !ret && folder->hide) { - /* Hide it */ - ad_init(&ad, vol); - if (ad_open(&ad, p, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0) { - free(p); - free(q); - return (-1); - } - - ad_setname(&ad, folder->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); - ad_close(&ad, ADFLAGS_HF); - } - free(p); - free(q); - return 0; -} - -static void handle_special_folders (const struct vol * vol) -{ - const _special_folder *p = &special_folders[0]; - - become_root(); - - for (; p->name != NULL; p++) { - create_special_folder (vol, p); - } - - unbecome_root(); -}