#include <atalk/iniparser.h>
#include <atalk/unix.h>
#include <atalk/netatalk_conf.h>
+#include <atalk/server_ipc.h>
#ifdef CNID_DB
#include <atalk/cnid.h>
extern int afprun(int root, char *cmd, int *outfd);
-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
*
DIR *dir = NULL;
const struct dirent *entry;
const char *p;
- struct stat st;
long int links;
time_t now = time(NULL);
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",
{
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 ) {
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
* .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 ) {
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;
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)
ashort |= VOLPBIT_ATTR_ACLS;
+ if (vol->v_casefold & AFPVOL_CASESENS)
+ ashort |= VOLPBIT_ATTR_CASESENS;
}
}
}
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;
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);
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;
*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 );
}
if ( NULL == (charset = find_charset_functions(volume->v_volcodepage)) || charset->flags & CHARSET_ICONV ) {
- LOG (log_warning, logtype_afpd, "WARNING: volume encoding %s is *not* supported by netatalk, expect problems !!!!", volume->v_volcodepage);
+ LOG (log_warning, logtype_afpd, "WARNING: volume encoding %s is *not* supported by netatalk, expect problems!", volume->v_volcodepage);
}
if (!volume->v_maccodepage)
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 */
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) {
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
*/
{
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;
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));
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 ) {
}
if ( volume == NULL ) {
- return AFPERR_PARAM;
+ return AFPERR_NOOBJ;
}
/* check for a volume password */
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;
/* initialize volume variables
* FIXME file size
*/
- if (utf8_encoding()) {
+ if (utf8_encoding(obj)) {
volume->max_filename = UTF8FILELEN_EARLY;
}
else {
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);
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,
ret = AFPERR_MISC;
goto openvol_err;
}
- free(vol_mname);
volume->v_root = dir;
curdir = dir;
* 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) {
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 );
}
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;
}
(void)chdir("/");
- closevol(vol);
+ curdir = NULL;
+ closevol(obj, vol);
+ server_ipc_volumes(obj);
return( AFP_OK );
}
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 )
/* 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);
}
}