X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fvolume.c;h=d15e9a4640a869d6baa1012796f37b3d03264ebd;hb=df7560dfdb12b06090dc4b2c6e88d0858930b591;hp=b6707b313699ea77646019f1ec44c068a8234ea2;hpb=14874ef66d68c5200a9a42a7408d022d58211898;p=netatalk.git diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index b6707b31..d15e9a46 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -36,6 +36,7 @@ #include #include #include +#include #ifdef CNID_DB #include @@ -236,7 +237,7 @@ static char *volxlate(AFPObj *obj, } else if (is_var(p, "$c")) { if (afpmaster && xlatevolname) return NULL; - DSI *dsi = obj->handle; + DSI *dsi = obj->dsi; len = sprintf(dest, "%s:%u", getip_string((struct sockaddr *)&dsi->client), getip_port((struct sockaddr *)&dsi->client)); @@ -263,7 +264,7 @@ static char *volxlate(AFPObj *obj, } else if (is_var(p, "$i")) { if (afpmaster && xlatevolname) return NULL; - DSI *dsi = obj->handle; + DSI *dsi = obj->dsi; q = getip_string((struct sockaddr *)&dsi->client); } else if (is_var(p, "$s")) { if (obj->Obj) @@ -404,15 +405,7 @@ static void volset(struct vol_option *options, struct vol_option *save, return; while (p) { - 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 | AFPVOL_USEDOTS; - } else if (strcasecmp(p, "crlf") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_CRLF; - else if (strcasecmp(p, "noadouble") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_NOADOUBLE; - else if (strcasecmp(p, "ro") == 0) + if (strcasecmp(p, "ro") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_RO; else if (strcasecmp(p, "nohex") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_NOHEX; @@ -420,10 +413,6 @@ static void volset(struct vol_option *options, struct vol_option *save, 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; - else if (strcasecmp(p, "nofileid") == 0) - options[VOLOPT_FLAGS].i_value |= AFPVOL_NOFILEID; else if (strcasecmp(p, "nostat") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_NOSTAT; else if (strcasecmp(p, "preexec_close") == 0) @@ -438,8 +427,6 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_FLAGS].i_value |= AFPVOL_CASEINSEN; else if (strcasecmp(p, "illegalseq") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_EILSEQ; - else if (strcasecmp(p, "nocnidcache") == 0) - options[VOLOPT_FLAGS].i_value &= ~AFPVOL_CACHE; else if (strcasecmp(p, "tm") == 0) options[VOLOPT_FLAGS].i_value |= AFPVOL_TM; else if (strcasecmp(p, "searchdb") == 0) @@ -448,6 +435,8 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_FLAGS].i_value |= AFPVOL_NONETIDS; else if (strcasecmp(p, "noacls") == 0) options[VOLOPT_FLAGS].i_value &= ~AFPVOL_ACLS; + else if (strcasecmp(p, "nov2toeaconv") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_NOV2TOEACONV; p = strtok(NULL, ","); } @@ -695,14 +684,10 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, 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 ((volume->v_flags & AFPVOL_NOADOUBLE)) - volume->v_ad_options |= ADVOL_NOADOUBLE; if (options[VOLOPT_PASSWORD].c_value) volume->v_password = strdup(options[VOLOPT_PASSWORD].c_value); @@ -895,7 +880,7 @@ static int hostaccessvol(int type, const char *volname, const char *args, const { int mask_int; char buf[MAXPATHLEN + 1], *p, *b; - DSI *dsi = obj->handle; + DSI *dsi = obj->dsi; struct sockaddr_storage client; if (!args) @@ -1102,6 +1087,7 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us int i; struct passwd *pw; struct vol_option save_options[VOLOPT_NUM]; + struct vol_option default_options[VOLOPT_NUM]; struct vol_option options[VOLOPT_NUM]; struct stat st; @@ -1144,17 +1130,17 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us break; } - memset(save_options, 0, sizeof(save_options)); + memset(default_options, 0, sizeof(default_options)); /* Enable some default options for all volumes */ - save_options[VOLOPT_FLAGS].i_value |= AFPVOL_CACHE; #ifdef HAVE_ACLS - save_options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS; + default_options[VOLOPT_FLAGS].i_value |= AFPVOL_ACLS; #endif - save_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO; + default_options[VOLOPT_EA_VFS].i_value = AFPVOL_EA_AUTO; LOG(log_maxdebug, logtype_afpd, "readvolfile: seeding default umask: %04o", obj->options.umask); - save_options[VOLOPT_UMASK].i_value = obj->options.umask; + default_options[VOLOPT_UMASK].i_value = obj->options.umask; + memcpy(save_options, default_options, sizeof(options)); LOG(log_debug, logtype_afpd, "readvolfile: \"%s\"", path); @@ -1169,12 +1155,14 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us case ':': /* change the default options for this file */ if (strncmp(path, VOLOPT_DEFAULT, VOLOPT_DEFAULT_LEN) == 0) { + volfree(default_options, save_options); + memcpy(default_options, save_options, sizeof(options)); *tmp = '\0'; for (i = 0; i < VOLOPT_NUM; i++) { if (parseline( sizeof( path ) - VOLOPT_DEFAULT_LEN - 1, path + VOLOPT_DEFAULT_LEN) < 0) break; - volset(save_options, NULL, tmp, sizeof(tmp) - 1, + volset(default_options, NULL, tmp, sizeof(tmp) - 1, path + VOLOPT_DEFAULT_LEN); } } @@ -1213,7 +1201,7 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us * able to specify things in any order, but i don't want to * re-write everything. */ - memcpy(options, save_options, sizeof(options)); + memcpy(options, default_options, sizeof(options)); *volname = '\0'; /* read in up to VOLOP_NUM possible options */ @@ -1221,7 +1209,7 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us if (parseline( sizeof( tmp ) - 1, tmp ) < 0) break; - volset(options, save_options, volname, sizeof(volname) - 1, tmp); + volset(options, default_options, volname, sizeof(volname) - 1, tmp); } /* check allow/deny lists (if not afpd master loading volumes for Zeroconf reg.): @@ -1252,7 +1240,7 @@ static int readvolfile(AFPObj *obj, struct afp_volume_name *p1, char *p2, int us creatvol(obj, pwent, path, tmp, options, p2 != NULL); } - volfree(options, save_options); + volfree(options, default_options); break; case '.' : @@ -1349,64 +1337,153 @@ static void volume_unlink(struct vol *volume) } } } - -static off_t getused_size; /* result of getused() */ - /*! - nftw callback for getused() + * Read band-size info from Info.plist XML file of an TM sparsebundle + * + * @param path (r) path to Info.plist file + * @return band-size in bytes, -1 on error */ -static int getused_stat(const char *path, - const struct stat *statp, - int tflag, - struct FTW *ftw) +static long long int get_tm_bandsize(const char *path) { - off_t low, high; + EC_INIT; + FILE *file = NULL; + char buf[512]; + long long int bandsize = -1; + + EC_NULL_LOGSTR( file = fopen(path, "r"), + "get_tm_bandsize(\"%s\"): %s", + path, strerror(errno) ); - if (tflag == FTW_F || tflag == FTW_D) { - getused_size += statp->st_blocks * 512; + while (fgets(buf, sizeof(buf), file) != NULL) { + if (strstr(buf, "band-size") == NULL) + continue; + + if (fscanf(file, " %lld", &bandsize) != 1) { + LOG(log_error, logtype_afpd, "get_tm_bandsize(\"%s\"): can't parse band-size", path); + EC_FAIL; + } + break; } - return 0; +EC_CLEANUP: + if (file) + fclose(file); + LOG(log_debug, logtype_afpd, "get_tm_bandsize(\"%s\"): bandsize: %lld", path, bandsize); + return bandsize; } -#define GETUSED_CACHETIME 5 /*! - * Calculate used size of a volume with nftw + * Return number on entries in a directory * - * The result is cached, we're try to avoid frequently calling nftw() + * @param path (r) path to dir + * @return number of entries, -1 on error + */ +static long long int get_tm_bands(const char *path) +{ + EC_INIT; + long long int count = 0; + DIR *dir = NULL; + const struct dirent *entry; + + EC_NULL( dir = opendir(path) ); + + while ((entry = readdir(dir)) != NULL) + count++; + count -= 2; /* All OSens I'm aware of return "." and "..", so just substract them, avoiding string comparison in loop */ + +EC_CLEANUP: + if (dir) + closedir(dir); + if (ret != 0) + return -1; + return count; +} + +/*! + * Calculate used size of a TimeMachine volume * - * 1) Call nftw an refresh if: - * 1a) - we're called the first time - * 1b) - volume modification date is not yet set and the last time we've been called is - * longer then 30 sec ago - * 1c) - the last volume modification is less then 30 sec old + * This assumes that the volume is used only for TimeMachine. + * + * 1) readdir(path of volume) + * 2) for every element that matches regex "\(.*\)\.sparsebundle$" : + * 3) parse "\1.sparsebundle/Info.plist" and read the band-size XML key integer value + * 4) readdir "\1.sparsebundle/bands/" counting files + * 5) calculate used size as: (file_count - 1) * band-size + * + * The result of the calculation is returned in "volume->v_tm_used". + * "volume->v_appended" gets reset to 0. + * "volume->v_tm_cachetime" is updated with the current time from time(NULL). + * + * "volume->v_tm_used" is cached for TM_USED_CACHETIME seconds and updated by + * "volume->v_appended". The latter is increased by X every time the client + * appends X bytes to a file (in fork.c). * * @param vol (rw) volume to calculate + * @return 0 on success, -1 on error */ -static int getused(struct vol *vol) +#define TM_USED_CACHETIME 60 /* cache for 60 seconds */ +static int get_tm_used(struct vol * restrict vol) { - static time_t vol_mtime = 0; - int ret = 0; + EC_INIT; + long long int bandsize; + VolSpace used = 0; + bstring infoplist = NULL; + bstring bandsdir = NULL; + DIR *dir = NULL; + const struct dirent *entry; + const char *p; + struct stat st; + long int links; time_t now = time(NULL); - if (!vol_mtime - || (!vol->v_mtime && ((vol_mtime + GETUSED_CACHETIME) < now)) - || (vol->v_mtime && ((vol_mtime + GETUSED_CACHETIME) < vol->v_mtime)) - ) { - vol_mtime = now; - getused_size = 0; - vol->v_written = 0; - ret = nftw(vol->v_path, getused_stat, NULL, 20, FTW_PHYS); /* 2 */ - LOG(log_debug, logtype_afpd, "volparams: from nftw: %" PRIu64 " bytes", - getused_size); - } else { - getused_size += vol->v_written; - vol->v_written = 0; - LOG(log_debug, logtype_afpd, "volparams: cached used: %" PRIu64 " bytes", - getused_size); + if (vol->v_tm_cachetime + && ((vol->v_tm_cachetime + TM_USED_CACHETIME) >= now)) { + if (vol->v_tm_used == -1) + EC_FAIL; + vol->v_tm_used += vol->v_appended; + vol->v_appended = 0; + LOG(log_debug, logtype_afpd, "getused(\"%s\"): cached: %" PRIu64 " bytes", + vol->v_path, vol->v_tm_used); + return 0; } - return ret; + vol->v_tm_cachetime = now; + + EC_NULL( dir = opendir(vol->v_path) ); + + while ((entry = readdir(dir)) != NULL) { + if (((p = strstr(entry->d_name, "sparsebundle")) != NULL) + && (strlen(entry->d_name) == (p + strlen("sparsebundle") - entry->d_name))) { + + EC_NULL_LOG( infoplist = bformat("%s/%s/%s", vol->v_path, entry->d_name, "Info.plist") ); + + if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) + continue; + + EC_NULL_LOG( bandsdir = bformat("%s/%s/%s/", vol->v_path, entry->d_name, "bands") ); + + if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) + continue; + + used += (links - 1) * bandsize; + LOG(log_debug, logtype_afpd, "getused(\"%s\"): bands: %" PRIu64 " bytes", + cfrombstr(bandsdir), used); + } + } + + vol->v_tm_used = used; + +EC_CLEANUP: + if (infoplist) + bdestroy(infoplist); + if (bandsdir) + bdestroy(bandsdir); + if (dir) + closedir(dir); + + LOG(log_debug, logtype_afpd, "getused(\"%s\"): %" PRIu64 " bytes", vol->v_path, vol->v_tm_used); + + EC_EXIT; } static int getvolspace(struct vol *vol, @@ -1422,9 +1499,7 @@ static int getvolspace(struct vol *vol, spaceflag = AFPVOL_GVSMASK & vol->v_flags; /* report up to 2GB if afp version is < 2.2 (4GB if not) */ - maxsize = (vol->v_flags & AFPVOL_A2VOL) ? 0x01fffe00 : - (((afp_version < 22) || (vol->v_flags & AFPVOL_LIMITSIZE)) - ? 0x7fffffffL : 0xffffffffL); + maxsize = (afp_version < 22) ? 0x7fffffffL : 0xffffffffL; #ifdef AFS if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_AFSGVS ) { @@ -1439,13 +1514,12 @@ static int getvolspace(struct vol *vol, return( rc ); } -#define min(a,b) ((a)<(b)?(a):(b)) #ifndef NO_QUOTA_SUPPORT if ( spaceflag == AFPVOL_NONE || spaceflag == AFPVOL_UQUOTA ) { if ( uquota_getvolspace( vol, &qfree, &qtotal, *bsize ) == AFP_OK ) { vol->v_flags = ( ~AFPVOL_GVSMASK & vol->v_flags ) | AFPVOL_UQUOTA; - *xbfree = min(*xbfree, qfree); - *xbtotal = min( *xbtotal, qtotal); + *xbfree = MIN(*xbfree, qfree); + *xbtotal = MIN(*xbtotal, qtotal); goto getvolspace_done; } } @@ -1454,18 +1528,19 @@ static int getvolspace(struct vol *vol, getvolspace_done: if (vol->v_limitsize) { - if (getused(vol) != 0) + if (get_tm_used(vol) != 0) return AFPERR_MISC; - LOG(log_debug, logtype_afpd, "volparams: used on volume: %" PRIu64 " bytes", - getused_size); - vol->v_tm_used = getused_size; - *xbtotal = min(*xbtotal, (vol->v_limitsize * 1024 * 1024)); - *xbfree = min(*xbfree, *xbtotal < getused_size ? 0 : *xbtotal - getused_size); + *xbtotal = MIN(*xbtotal, (vol->v_limitsize * 1024 * 1024)); + *xbfree = MIN(*xbfree, *xbtotal < vol->v_tm_used ? 0 : *xbtotal - vol->v_tm_used); + + LOG(log_debug, logtype_afpd, + "volparams: total: %" PRIu64 ", used: %" PRIu64 ", free: %" PRIu64 " bytes", + *xbtotal, vol->v_tm_used, *xbfree); } - *bfree = min( *xbfree, maxsize); - *btotal = min( *xbtotal, maxsize); + *bfree = MIN(*xbfree, maxsize); + *btotal = MIN(*xbtotal, maxsize); return( AFP_OK ); } @@ -1480,7 +1555,7 @@ void vol_fce_tm_event(void) 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_written); + (void)fce_register_tm_size(vol->v_path, vol->v_tm_used + vol->v_appended); } } } @@ -1525,8 +1600,11 @@ static int getvolparams( uint16_t bitmap, struct vol *vol, struct stat *st, char * For MacOS8.x support we need to create the * .Parent file here if it doesn't exist. */ - ad_init(&ad, vol->v_adouble, vol->v_ad_options); - if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0 ) { + /* Convert adouble:v2 to adouble:ea on the fly */ + (void)ad_convert(vol->v_path, st, vol); + + ad_init(&ad, vol); + if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0 ) { isad = 0; vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime); @@ -1583,10 +1661,8 @@ static int getvolparams( uint16_t bitmap, struct vol *vol, struct stat *st, char } /* prior 2.1 only VOLPBIT_ATTR_RO is defined */ if (afp_version > 20) { - if (0 == (vol->v_flags & AFPVOL_NOFILEID) && vol->v_cdb != NULL && - (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) { + if (vol->v_cdb != NULL && (vol->v_cdb->flags & CNID_FLAG_PERSISTENT)) ashort |= VOLPBIT_ATTR_FILEID; - } ashort |= VOLPBIT_ATTR_CATSEARCH; if (afp_version >= 30) { @@ -1703,7 +1779,7 @@ static int getvolparams( uint16_t bitmap, struct vol *vol, struct stat *st, char data += aint; } if ( isad ) { - ad_close_metadata( &ad); + ad_close(&ad, ADFLAGS_HF); } *buflen = data - buf; return( AFP_OK ); @@ -1836,7 +1912,7 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf if (!S_ISDIR(st.st_mode)) { continue; /* not a dir */ } - accessmode(volume->v_path, &ma, NULL, &st); + accessmode(volume, volume->v_path, &ma, NULL, &st); if ((ma.ma_user & (AR_UREAD | AR_USEARCH)) != (AR_UREAD | AR_USEARCH)) { continue; /* no r-x access */ } @@ -1857,13 +1933,6 @@ int afp_getsrvrparms(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf /* set password bit if there's a volume password */ *data = (volume->v_password) ? AFPSRVR_PASSWD : 0; - /* Apple 2 clients running ProDOS-8 expect one volume to have - bit 0 of this byte set. They will not recognize anything - on the server unless this is the case. I have not - completely worked this out, but it's related to booting - from the server. Support for that function is a ways - 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 */ *data++ = len; memcpy(data, namebuf, len ); @@ -1983,7 +2052,6 @@ static int volume_openDB(struct vol *volume) "Check server messages for details!"); kill(getpid(), SIGUSR2); /* deactivate cnid caching/storing in AppleDouble files */ - volume->v_flags &= ~AFPVOL_CACHE; } #endif } @@ -2426,7 +2494,7 @@ int pollvoltime(AFPObj *obj) if ( (vol->v_flags & AFPVOL_OPEN) && vol->v_mtime + 30 < tv.tv_sec) { if ( !stat( vol->v_path, &st ) && vol->v_mtime != st.st_mtime ) { vol->v_mtime = st.st_mtime; - if (!obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED)) + if (!obj->attention(obj->dsi, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED)) return -1; return 1; } @@ -2457,7 +2525,7 @@ void setvoltime(AFPObj *obj, struct vol *vol) * AFP 3.2 and above clients seem to be ok without so many notification */ if (afp_version < 32 && obj->options.server_notif) { - obj->attention(obj->handle, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED); + obj->attention(obj->dsi, AFPATTN_NOTIFY | AFPATTN_VOLCHANGED); } } } @@ -2510,8 +2578,8 @@ int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf if (bitmap != (1 << VOLPBIT_BDATE)) return AFPERR_BITMAP; - ad_init(&ad, vol->v_adouble, vol->v_ad_options); - if ( ad_open(&ad, vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR) < 0 ) { + ad_init(&ad, vol); + if ( ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR) < 0 ) { if (errno == EROFS) return AFPERR_VLOCK; @@ -2525,33 +2593,6 @@ int afp_setvolparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf return( AFP_OK ); } -/* ------------------------- */ -int wincheck(const struct vol *vol, const char *path) -{ - int len; - - if (!(vol->v_flags & AFPVOL_MSWINDOWS)) - return 1; - - /* empty paths are not allowed */ - if ((len = strlen(path)) == 0) - return 0; - - /* leading or trailing whitespaces are not allowed, carriage returns - * and probably other whitespace is okay, tabs are not allowed - */ - if ((path[0] == ' ') || (path[len-1] == ' ')) - return 0; - - /* certain characters are not allowed */ - if (strpbrk(path, MSWINDOWS_BADCHARS)) - return 0; - - /* everything else is okay */ - return 1; -} - - /* * precreate a folder * this is only intended for folders in the volume root @@ -2605,8 +2646,8 @@ 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, vol->v_ad_options); - if (ad_open(&ad, p, ADFLAGS_HF | ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0) { + 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); @@ -2625,8 +2666,8 @@ static int create_special_folder (const struct vol *vol, const struct _special_f memcpy(ad_entry(&ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF,&attr, sizeof(attr)); } - ad_flush( &ad ); - ad_close_metadata( &ad); + ad_flush(&ad); + ad_close(&ad, ADFLAGS_HF); } free(p); free(q);