2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
8 #endif /* HAVE_CONFIG_H */
18 #include <sys/param.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
25 #include <atalk/dsi.h>
26 #include <atalk/adouble.h>
27 #include <atalk/afp.h>
28 #include <atalk/util.h>
29 #include <atalk/logger.h>
30 #include <atalk/vfs.h>
31 #include <atalk/uuid.h>
33 #include <atalk/bstrlib.h>
34 #include <atalk/bstradd.h>
35 #include <atalk/ftw.h>
36 #include <atalk/globals.h>
37 #include <atalk/fce_api.h>
38 #include <atalk/errchk.h>
39 #include <atalk/iniparser.h>
40 #include <atalk/unix.h>
41 #include <atalk/netatalk_conf.h>
42 #include <atalk/server_ipc.h>
45 #include <atalk/cnid.h>
48 #include "directory.h"
59 extern int afprun(int root, char *cmd, int *outfd);
62 * Read band-size info from Info.plist XML file of an TM sparsebundle
64 * @param path (r) path to Info.plist file
65 * @return band-size in bytes, -1 on error
67 static long long int get_tm_bandsize(const char *path)
72 long long int bandsize = -1;
74 EC_NULL_LOGSTR( file = fopen(path, "r"),
75 "get_tm_bandsize(\"%s\"): %s",
76 path, strerror(errno) );
78 while (fgets(buf, sizeof(buf), file) != NULL) {
79 if (strstr(buf, "band-size") == NULL)
82 if (fscanf(file, " <integer>%lld</integer>", &bandsize) != 1) {
83 LOG(log_error, logtype_afpd, "get_tm_bandsize(\"%s\"): can't parse band-size", path);
92 LOG(log_debug, logtype_afpd, "get_tm_bandsize(\"%s\"): bandsize: %lld", path, bandsize);
97 * Return number on entries in a directory
99 * @param path (r) path to dir
100 * @return number of entries, -1 on error
102 static long long int get_tm_bands(const char *path)
105 long long int count = 0;
107 const struct dirent *entry;
109 EC_NULL( dir = opendir(path) );
111 while ((entry = readdir(dir)) != NULL)
113 count -= 2; /* All OSens I'm aware of return "." and "..", so just substract them, avoiding string comparison in loop */
124 * Calculate used size of a TimeMachine volume
126 * This assumes that the volume is used only for TimeMachine.
128 * 1) readdir(path of volume)
129 * 2) for every element that matches regex "\(.*\)\.sparsebundle$" :
130 * 3) parse "\1.sparsebundle/Info.plist" and read the band-size XML key integer value
131 * 4) readdir "\1.sparsebundle/bands/" counting files
132 * 5) calculate used size as: (file_count - 1) * band-size
134 * The result of the calculation is returned in "volume->v_tm_used".
135 * "volume->v_appended" gets reset to 0.
136 * "volume->v_tm_cachetime" is updated with the current time from time(NULL).
138 * "volume->v_tm_used" is cached for TM_USED_CACHETIME seconds and updated by
139 * "volume->v_appended". The latter is increased by X every time the client
140 * appends X bytes to a file (in fork.c).
142 * @param vol (rw) volume to calculate
143 * @return 0 on success, -1 on error
145 #define TM_USED_CACHETIME 60 /* cache for 60 seconds */
146 static int get_tm_used(struct vol * restrict vol)
149 long long int bandsize;
151 bstring infoplist = NULL;
152 bstring bandsdir = NULL;
154 const struct dirent *entry;
157 time_t now = time(NULL);
159 if (vol->v_tm_cachetime
160 && ((vol->v_tm_cachetime + TM_USED_CACHETIME) >= now)) {
161 if (vol->v_tm_used == -1)
163 vol->v_tm_used += vol->v_appended;
165 LOG(log_debug, logtype_afpd, "getused(\"%s\"): cached: %" PRIu64 " bytes",
166 vol->v_path, vol->v_tm_used);
170 vol->v_tm_cachetime = now;
172 EC_NULL( dir = opendir(vol->v_path) );
174 while ((entry = readdir(dir)) != NULL) {
175 if (((p = strstr(entry->d_name, "sparsebundle")) != NULL)
176 && (strlen(entry->d_name) == (p + strlen("sparsebundle") - entry->d_name))) {
178 EC_NULL_LOG( infoplist = bformat("%s/%s/%s", vol->v_path, entry->d_name, "Info.plist") );
180 if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) {
185 EC_NULL_LOG( bandsdir = bformat("%s/%s/%s/", vol->v_path, entry->d_name, "bands") );
187 if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) {
193 used += (links - 1) * bandsize;
194 LOG(log_debug, logtype_afpd, "getused(\"%s\"): bands: %" PRIu64 " bytes",
195 cfrombstr(bandsdir), used);
199 vol->v_tm_used = used;
209 LOG(log_debug, logtype_afpd, "getused(\"%s\"): %" PRIu64 " bytes", vol->v_path, vol->v_tm_used);
214 static int getvolspace(const AFPObj *obj, struct vol *vol,
215 uint32_t *bfree, uint32_t *btotal,
216 VolSpace *xbfree, VolSpace *xbtotal, uint32_t *bsize)
220 #ifndef NO_QUOTA_SUPPORT
221 VolSpace qfree, qtotal;
224 spaceflag = AFPVOL_GVSMASK & vol->v_flags;
225 /* report up to 2GB if afp version is < 2.2 (4GB if not) */
226 maxsize = (obj->afp_version < 22) ? 0x7fffffffL : 0xffffffffL;
229 if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_AFSGVS ) {
230 if ( afs_getvolspace( vol, xbfree, xbtotal, bsize ) == AFP_OK ) {
231 vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_AFSGVS;
232 goto getvolspace_done;
237 if (( rc = ustatfs_getvolspace( vol, xbfree, xbtotal, bsize)) != AFP_OK ) {
241 #ifndef NO_QUOTA_SUPPORT
242 if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_UQUOTA ) {
243 if ( uquota_getvolspace(obj, vol, &qfree, &qtotal, *bsize ) == AFP_OK ) {
244 vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_UQUOTA;
245 *xbfree = MIN(*xbfree, qfree);
246 *xbtotal = MIN(*xbtotal, qtotal);
247 goto getvolspace_done;
251 vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_USTATFS;
254 if (vol->v_limitsize) {
255 if (get_tm_used(vol) != 0)
258 *xbtotal = MIN(*xbtotal, (vol->v_limitsize * 1024 * 1024));
259 *xbfree = MIN(*xbfree, *xbtotal < vol->v_tm_used ? 0 : *xbtotal - vol->v_tm_used);
261 LOG(log_debug, logtype_afpd,
262 "volparams: total: %" PRIu64 ", used: %" PRIu64 ", free: %" PRIu64 " bytes",
263 *xbtotal, vol->v_tm_used, *xbfree);
266 *bfree = MIN(*xbfree, maxsize);
267 *btotal = MIN(*xbtotal, maxsize);
271 /* -----------------------
272 * set volume creation date
273 * avoid duplicate, well at least it tries
275 static void vol_setdate(uint16_t id, struct adouble *adp, time_t date)
278 struct vol *vol = getvolumes();
280 for ( volume = getvolumes(); volume; volume = volume->v_next ) {
281 if (volume->v_vid == id) {
284 else if ((time_t)(AD_DATE_FROM_UNIX(date)) == volume->v_ctime) {
286 volume = getvolumes(); /* restart */
289 vol->v_ctime = AD_DATE_FROM_UNIX(date);
290 ad_setdate(adp, AD_DATE_CREATE | AD_DATE_UNIX, date);
293 /* ----------------------- */
294 static int getvolparams(const AFPObj *obj, uint16_t bitmap, struct vol *vol, struct stat *st, char *buf, size_t *buflen)
297 int bit = 0, isad = 1;
300 uint32_t bfree, btotal, bsize;
301 VolSpace xbfree, xbtotal; /* extended bytes */
302 char *data, *nameoff = NULL;
305 LOG(log_debug, logtype_afpd, "getvolparams: Volume '%s'", vol->v_localname);
307 /* courtesy of jallison@whistle.com:
308 * For MacOS8.x support we need to create the
309 * .Parent file here if it doesn't exist. */
311 /* Convert adouble:v2 to adouble:ea on the fly */
312 (void)ad_convert(vol->v_path, st, vol, NULL);
315 if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) {
317 vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
319 } else if (ad_get_MD_flags( &ad ) & O_CREAT) {
320 slash = strrchr( vol->v_path, '/' );
325 if (ad_getentryoff(&ad, ADEID_NAME)) {
326 ad_setentrylen( &ad, ADEID_NAME, strlen( slash ));
327 memcpy(ad_entry( &ad, ADEID_NAME ), slash,
328 ad_getentrylen( &ad, ADEID_NAME ));
330 vol_setdate(vol->v_vid, &ad, st->st_mtime);
334 if (ad_getdate(&ad, AD_DATE_CREATE, &aint) < 0)
335 vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
340 if (( bitmap & ( (1<<VOLPBIT_BFREE)|(1<<VOLPBIT_BTOTAL) |
341 (1<<VOLPBIT_XBFREE)|(1<<VOLPBIT_XBTOTAL) |
342 (1<<VOLPBIT_BSIZE)) ) != 0 ) {
343 if ( getvolspace(obj, vol, &bfree, &btotal, &xbfree, &xbtotal,
344 &bsize) != AFP_OK ) {
346 ad_close( &ad, ADFLAGS_HF );
348 return( AFPERR_PARAM );
353 while ( bitmap != 0 ) {
354 while (( bitmap & 1 ) == 0 ) {
362 /* check for read-only.
363 * NOTE: we don't actually set the read-only flag unless
364 * it's passed in that way as it's possible to mount
365 * a read-write filesystem under a read-only one. */
366 if ((vol->v_flags & AFPVOL_RO) ||
367 ((utime(vol->v_path, NULL) < 0) && (errno == EROFS))) {
368 ashort |= VOLPBIT_ATTR_RO;
370 /* prior 2.1 only VOLPBIT_ATTR_RO is defined */
371 if (obj->afp_version > 20) {
372 if (vol->v_cdb != NULL && (vol->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT))
373 ashort |= VOLPBIT_ATTR_FILEID;
374 ashort |= VOLPBIT_ATTR_CATSEARCH;
376 if (obj->afp_version >= 30) {
377 ashort |= VOLPBIT_ATTR_UTF8;
378 if (vol->v_flags & AFPVOL_UNIX_PRIV)
379 ashort |= VOLPBIT_ATTR_UNIXPRIV;
380 if (vol->v_flags & AFPVOL_TM)
381 ashort |= VOLPBIT_ATTR_TM;
382 if (vol->v_flags & AFPVOL_NONETIDS)
383 ashort |= VOLPBIT_ATTR_NONETIDS;
384 if (obj->afp_version >= 32) {
386 ashort |= VOLPBIT_ATTR_EXT_ATTRS;
387 if (vol->v_flags & AFPVOL_ACLS)
388 ashort |= VOLPBIT_ATTR_ACLS;
389 if (vol->v_casefold & AFPVOL_CASESENS)
390 ashort |= VOLPBIT_ATTR_CASESENS;
394 ashort = htons(ashort);
395 memcpy(data, &ashort, sizeof( ashort ));
396 data += sizeof( ashort );
400 ashort = htons( AFPVOLSIG_DEFAULT );
401 memcpy(data, &ashort, sizeof( ashort ));
402 data += sizeof( ashort );
407 memcpy(data, &aint, sizeof( aint ));
408 data += sizeof( aint );
412 if ( st->st_mtime > vol->v_mtime ) {
413 vol->v_mtime = st->st_mtime;
415 aint = AD_DATE_FROM_UNIX(vol->v_mtime);
416 memcpy(data, &aint, sizeof( aint ));
417 data += sizeof( aint );
421 if (!isad || (ad_getdate(&ad, AD_DATE_BACKUP, &aint) < 0))
422 aint = AD_DATE_START;
423 memcpy(data, &aint, sizeof( aint ));
424 data += sizeof( aint );
428 memcpy(data, &vol->v_vid, sizeof( vol->v_vid ));
429 data += sizeof( vol->v_vid );
433 bfree = htonl( bfree );
434 memcpy(data, &bfree, sizeof( bfree ));
435 data += sizeof( bfree );
438 case VOLPBIT_BTOTAL :
439 btotal = htonl( btotal );
440 memcpy(data, &btotal, sizeof( btotal ));
441 data += sizeof( btotal );
444 #ifndef NO_LARGE_VOL_SUPPORT
445 case VOLPBIT_XBFREE :
446 xbfree = hton64( xbfree );
447 memcpy(data, &xbfree, sizeof( xbfree ));
448 data += sizeof( xbfree );
451 case VOLPBIT_XBTOTAL :
452 xbtotal = hton64( xbtotal );
453 memcpy(data, &xbtotal, sizeof( xbtotal ));
454 data += sizeof( xbfree );
456 #endif /* ! NO_LARGE_VOL_SUPPORT */
460 data += sizeof( uint16_t );
463 case VOLPBIT_BSIZE: /* block size */
464 bsize = htonl(bsize);
465 memcpy(data, &bsize, sizeof(bsize));
466 data += sizeof(bsize);
471 ad_close( &ad, ADFLAGS_HF );
473 return( AFPERR_BITMAP );
479 ashort = htons( data - buf );
480 memcpy(nameoff, &ashort, sizeof( ashort ));
481 /* name is always in mac charset */
482 aint = ucs2_to_charset( vol->v_maccharset, vol->v_macname, data+1, AFPVOL_MACNAMELEN + 1);
492 ad_close(&ad, ADFLAGS_HF);
494 *buflen = data - buf;
498 /* ------------------------- */
499 static int stat_vol(const AFPObj *obj, uint16_t bitmap, struct vol *vol, char *rbuf, size_t *rbuflen)
505 if ( stat( vol->v_path, &st ) < 0 ) {
507 return( AFPERR_PARAM );
509 /* save the volume device number */
510 vol->v_dev = st.st_dev;
512 buflen = *rbuflen - sizeof( bitmap );
513 if (( ret = getvolparams(obj, bitmap, vol, &st,
514 rbuf + sizeof( bitmap ), &buflen )) != AFP_OK ) {
518 *rbuflen = buflen + sizeof( bitmap );
519 bitmap = htons( bitmap );
520 memcpy(rbuf, &bitmap, sizeof( bitmap ));
525 /* ------------------------------- */
526 int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
537 load_volumes(obj, lv_none);
540 for ( vcnt = 0, volume = getvolumes(); volume && vcnt < 255; volume = volume->v_next ) {
541 if (!(volume->v_flags & AFPVOL_NOSTAT)) {
544 if ( stat( volume->v_path, &st ) < 0 ) {
545 LOG(log_info, logtype_afpd, "afp_getsrvrparms(%s): stat: %s",
546 volume->v_path, strerror(errno) );
547 continue; /* can't access directory */
549 if (!S_ISDIR(st.st_mode)) {
550 continue; /* not a dir */
552 accessmode(obj, volume, volume->v_path, &ma, NULL, &st);
553 if ((ma.ma_user & (AR_UREAD | AR_USEARCH)) != (AR_UREAD | AR_USEARCH)) {
554 continue; /* no r-x access */
558 if (utf8_encoding(obj)) {
559 len = ucs2_to_charset_allocate(CH_UTF8_MAC, &namebuf, volume->v_u8mname);
561 len = ucs2_to_charset_allocate(obj->options.maccharset, &namebuf, volume->v_macname);
564 if (len == (size_t)-1)
568 * There seems to be an undocumented limit on how big our reply can get
569 * before the client chokes and closes the connection.
570 * Testing with 10.8.4 found the limit at ~4600 bytes. Go figure.
572 if (((data + len + 3) - rbuf) > 4600)
575 /* set password bit if there's a volume password */
576 *data = (volume->v_password) ? AFPSRVR_PASSWD : 0;
578 *data++ |= 0; /* UNIX PRIVS BIT ..., OSX doesn't seem to use it, so we don't either */
580 memcpy(data, namebuf, len );
586 *rbuflen = data - rbuf;
588 if ( gettimeofday( &tv, NULL ) < 0 ) {
589 LOG(log_error, logtype_afpd, "afp_getsrvrparms: gettimeofday: %s", strerror(errno) );
594 aint = AD_DATE_FROM_UNIX(tv.tv_sec);
595 memcpy(data, &aint, sizeof( uint32_t));
596 data += sizeof( uint32_t);
601 /* ------------------------- */
602 static int volume_codepage(AFPObj *obj, struct vol *volume)
604 struct charset_functions *charset;
607 if (!volume->v_volcodepage)
608 volume->v_volcodepage = strdup("UTF8");
610 if ( (charset_t) -1 == ( volume->v_volcharset = add_charset(volume->v_volcodepage)) ) {
611 LOG (log_error, logtype_afpd, "Setting codepage %s as volume codepage failed", volume->v_volcodepage);
615 if ( NULL == (charset = find_charset_functions(volume->v_volcodepage)) || charset->flags & CHARSET_ICONV ) {
616 LOG (log_warning, logtype_afpd, "WARNING: volume encoding %s is *not* supported by netatalk, expect problems !!!!", volume->v_volcodepage);
619 if (!volume->v_maccodepage)
620 volume->v_maccodepage = strdup(obj->options.maccodepage);
622 if ( (charset_t) -1 == ( volume->v_maccharset = add_charset(volume->v_maccodepage)) ) {
623 LOG (log_error, logtype_afpd, "Setting codepage %s as mac codepage failed", volume->v_maccodepage);
627 if ( NULL == ( charset = find_charset_functions(volume->v_maccodepage)) || ! (charset->flags & CHARSET_CLIENT) ) {
628 LOG (log_error, logtype_afpd, "Fatal error: mac charset %s not supported", volume->v_maccodepage);
631 volume->v_kTextEncoding = htonl(charset->kTextEncoding);
635 /* ------------------------- */
636 static int volume_openDB(const AFPObj *obj, struct vol *volume)
640 if ((volume->v_flags & AFPVOL_NODEV)) {
641 flags |= CNID_FLAG_NODEV;
644 volume->v_cdb = cnid_open(volume, volume->v_cnidscheme, flags);
646 if ( ! volume->v_cdb && ! (flags & CNID_FLAG_MEMORY)) {
647 /* The first attempt failed and it wasn't yet an attempt to open in-memory */
648 LOG(log_error, logtype_afpd, "Can't open volume \"%s\" CNID backend \"%s\" ",
649 volume->v_path, volume->v_cnidscheme);
650 LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
652 flags |= CNID_FLAG_MEMORY;
653 volume->v_cdb = cnid_open(volume, "tdb", flags);
655 /* kill ourself with SIGUSR2 aka msg pending */
657 setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB instead."
658 "Check server messages for details!");
659 kill(getpid(), SIGUSR2);
660 /* deactivate cnid caching/storing in AppleDouble files */
665 return (!volume->v_cdb)?-1:0;
669 * Send list of open volumes to afpd master via IPC
671 static void server_ipc_volumes(AFPObj *obj)
673 struct vol *volume, *vols;
674 volume = vols = getvolumes();
675 bstring openvolnames = bfromcstr("");
676 bool firstvol = true;
679 if (volume->v_flags & AFPVOL_OPEN) {
681 bcatcstr(openvolnames, ", ");
684 bcatcstr(openvolnames, volume->v_localname);
686 volume = volume->v_next;
689 ipc_child_write(obj->ipc_fd, IPC_VOLUMES, blength(openvolnames), bdata(openvolnames));
690 bdestroy(openvolnames);
693 /* -------------------------
694 * we are the user here
696 int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
707 char *vol_mname = NULL;
711 memcpy(&bitmap, ibuf, sizeof( bitmap ));
712 bitmap = ntohs( bitmap );
713 ibuf += sizeof( bitmap );
716 if (( bitmap & (1<<VOLPBIT_VID)) == 0 ) {
717 return AFPERR_BITMAP;
720 len = (unsigned char)*ibuf++;
721 volname = obj->oldtmp;
723 if ((volname_tmp = strchr(volname,'+')) != NULL)
724 volname = volname_tmp+1;
726 if (utf8_encoding(obj)) {
727 namelen = convert_string(CH_UTF8_MAC, CH_UCS2, ibuf, len, volname, sizeof(obj->oldtmp));
729 namelen = convert_string(obj->options.maccharset, CH_UCS2, ibuf, len, volname, sizeof(obj->oldtmp));
737 if ((len + 1) & 1) /* pad to an even boundary */
740 load_volumes(obj, lv_none);
742 for ( volume = getvolumes(); volume; volume = volume->v_next ) {
743 if ( strcasecmp_w( (ucs2_t*) volname, volume->v_name ) == 0 ) {
748 if ( volume == NULL ) {
752 /* check for a volume password */
753 if (volume->v_password && strncmp(ibuf, volume->v_password, VOLPASSLEN)) {
754 return AFPERR_ACCESS;
757 if (( volume->v_flags & AFPVOL_OPEN ) ) {
758 /* the volume is already open */
759 return stat_vol(obj, bitmap, volume, rbuf, rbuflen);
762 if (volume->v_root_preexec) {
763 if ((ret = afprun(1, volume->v_root_preexec, NULL)) && volume->v_root_preexec_close) {
764 LOG(log_error, logtype_afpd, "afp_openvol(%s): root preexec : %d", volume->v_path, ret );
769 if (volume->v_preexec) {
770 if ((ret = afprun(0, volume->v_preexec, NULL)) && volume->v_preexec_close) {
771 LOG(log_error, logtype_afpd, "afp_openvol(%s): preexec : %d", volume->v_path, ret );
776 if ( stat( volume->v_path, &st ) < 0 ) {
780 if ( chdir( volume->v_path ) < 0 ) {
784 if (volume_codepage(obj, volume) < 0) {
789 /* initialize volume variables
792 if (utf8_encoding(obj)) {
793 volume->max_filename = UTF8FILELEN_EARLY;
796 volume->max_filename = MACFILELEN;
799 volume->v_flags |= AFPVOL_OPEN;
800 volume->v_cdb = NULL;
802 if (utf8_encoding(obj)) {
803 len = convert_string_allocate(CH_UCS2, CH_UTF8_MAC, volume->v_u8mname, namelen, &vol_mname);
805 len = convert_string_allocate(CH_UCS2, obj->options.maccharset, volume->v_macname, namelen, &vol_mname);
807 if ( !vol_mname || len <= 0) {
812 if ((vol_uname = strrchr(volume->v_path, '/')) == NULL)
813 vol_uname = volume->v_path;
814 else if (vol_uname[1] != '\0')
817 if ((dir = dir_new(vol_mname,
822 bfromcstr(volume->v_path),
826 LOG(log_error, logtype_afpd, "afp_openvol(%s): malloc: %s", volume->v_path, strerror(errno) );
830 volume->v_root = dir;
833 if (volume_openDB(obj, volume) < 0) {
834 LOG(log_error, logtype_afpd, "Fatal error: cannot open CNID or invalid CNID backend for %s: %s",
835 volume->v_path, volume->v_cnidscheme);
840 ret = stat_vol(obj, bitmap, volume, rbuf, rbuflen);
844 * If you mount a volume twice, the second time the trash appears on
845 * the desk-top. That's because the Mac remembers the DID for the
846 * trash (even for volumes in different zones, on different servers).
847 * Just so this works better, we prime the DID cache with the trash,
848 * fixing the trash at DID 17.
849 * FIXME (RL): should it be done inside a CNID backend ? (always returning Trash DID when asked) ?
851 if ((volume->v_cdb->cnid_db_flags & CNID_FLAG_PERSISTENT)) {
853 /* FIXME find db time stamp */
854 if (cnid_getstamp(volume->v_cdb, volume->v_stamp, sizeof(volume->v_stamp)) < 0) {
855 LOG (log_error, logtype_afpd,
856 "afp_openvol(%s): Fatal error: Unable to get stamp value from CNID backend",
864 if ((msg = atalk_iniparser_getstring(obj->iniconfig, volume->v_configname, "login message", NULL)) != NULL)
868 server_ipc_volumes(obj);
873 if (volume->v_root) {
874 dir_free( volume->v_root );
875 volume->v_root = NULL;
878 volume->v_flags &= ~AFPVOL_OPEN;
879 if (volume->v_cdb != NULL) {
880 cnid_close(volume->v_cdb);
881 volume->v_cdb = NULL;
888 void closevol(const AFPObj *obj, struct vol *vol)
893 vol->v_flags &= ~AFPVOL_OPEN;
895 of_closevol(obj, vol);
897 dir_free( vol->v_root );
899 if (vol->v_cdb != NULL) {
900 cnid_close(vol->v_cdb);
904 if (vol->v_postexec) {
905 afprun(0, vol->v_postexec, NULL);
907 if (vol->v_root_postexec) {
908 afprun(1, vol->v_root_postexec, NULL);
912 /* ------------------------- */
913 void close_all_vol(const AFPObj *obj)
917 for ( ovol = getvolumes(); ovol; ovol = ovol->v_next ) {
918 if ( (ovol->v_flags & AFPVOL_OPEN) ) {
919 ovol->v_flags &= ~AFPVOL_OPEN;
925 /* ------------------------- */
926 int afp_closevol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
933 memcpy(&vid, ibuf, sizeof( vid ));
934 if (NULL == ( vol = getvolbyvid( vid )) ) {
935 return( AFPERR_PARAM );
941 server_ipc_volumes(obj);
946 /* --------------------------
947 poll if a volume is changed by other processes.
949 0 no attention msg sent
951 -1 error (socket closed)
953 Note: if attention return -1 no packet has been
954 sent because the buffer is full, we don't care
955 either there's no reader or there's a lot of
956 traffic and another pollvoltime will follow
958 int pollvoltime(AFPObj *obj)
965 if (!(obj->afp_version > 21 && obj->options.flags & OPTION_SERVERNOTIF))
968 if ( gettimeofday( &tv, NULL ) < 0 )
971 for ( vol = getvolumes(); vol; vol = vol->v_next ) {
972 if ( (vol->v_flags & AFPVOL_OPEN) && vol->v_mtime + 30 < tv.tv_sec) {
973 if ( !stat( vol->v_path, &st ) && vol->v_mtime != st.st_mtime ) {
974 vol->v_mtime = st.st_mtime;
975 if (!obj->attention(obj->dsi, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED))
984 /* ------------------------- */
985 void setvoltime(AFPObj *obj, struct vol *vol)
989 if ( gettimeofday( &tv, NULL ) < 0 ) {
990 LOG(log_error, logtype_afpd, "setvoltime(%s): gettimeofday: %s", vol->v_path, strerror(errno) );
993 if( utime( vol->v_path, NULL ) < 0 ) {
994 /* write of time failed ... probably a read only filesys,
995 * where no other users can interfere, so there's no issue here
999 /* a little granularity */
1000 if (vol->v_mtime < tv.tv_sec) {
1001 vol->v_mtime = tv.tv_sec;
1002 /* or finder doesn't update free space
1003 * AFP 3.2 and above clients seem to be ok without so many notification
1005 if (obj->afp_version < 32 && obj->options.flags & OPTION_SERVERNOTIF) {
1006 obj->attention(obj->dsi, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED);
1011 /* ------------------------- */
1012 int afp_getvolparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_,char *rbuf, size_t *rbuflen)
1015 uint16_t vid, bitmap;
1018 memcpy(&vid, ibuf, sizeof( vid ));
1019 ibuf += sizeof( vid );
1020 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1021 bitmap = ntohs( bitmap );
1023 if (NULL == ( vol = getvolbyvid( vid )) ) {
1025 return( AFPERR_PARAM );
1028 return stat_vol(obj, bitmap, vol, rbuf, rbuflen);
1031 /* ------------------------- */
1032 int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
1036 uint16_t vid, bitmap;
1042 memcpy(&vid, ibuf, sizeof( vid ));
1043 ibuf += sizeof( vid );
1044 memcpy(&bitmap, ibuf, sizeof( bitmap ));
1045 bitmap = ntohs( bitmap );
1046 ibuf += sizeof(bitmap);
1048 if (( vol = getvolbyvid( vid )) == NULL ) {
1049 return( AFPERR_PARAM );
1052 if ((vol->v_flags & AFPVOL_RO))
1053 return AFPERR_VLOCK;
1055 /* we can only set the backup date. */
1056 if (bitmap != (1 << VOLPBIT_BDATE))
1057 return AFPERR_BITMAP;
1060 if ( ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR) < 0 ) {
1062 return AFPERR_VLOCK;
1064 return AFPERR_ACCESS;
1067 memcpy(&aint, ibuf, sizeof(aint));
1068 ad_setdate(&ad, AD_DATE_BACKUP, aint);
1070 ad_close(&ad, ADFLAGS_HF);