-2.2alpha5
\ No newline at end of file
+3.0dev
\ No newline at end of file
# Makefile.am for bin/
-SUBDIRS = ad adv1tov2 afppasswd cnid megatron uniconv misc
+SUBDIRS = ad afppasswd cnid megatron uniconv misc
if USE_APPLETALK
SUBDIRS += aecho getzones nbp pap psorder
extern int ad_cp(int argc, char **argv);
extern int ad_rm(int argc, char **argv);
extern int ad_mv(int argc, char **argv);
+extern int ad_find(int argc, char **argv);
/* ad_util.c */
extern int openvol(const char *path, afpvol_t *vol);
break;
}
ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
- if (ad_open_metadata(to.p_path, ADFLAGS_DIR, O_RDWR | O_CREAT, &ad) != 0) {
+ if (ad_open(&ad, to.p_path, ADFLAGS_HF | ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0) {
ERROR("Error opening adouble for: %s", to.p_path);
}
ad_setid( &ad, st.st_dev, st.st_ino, did, pdid, dvolume.db_stamp);
break;
}
ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
- if (ad_open_metadata(to.p_path, 0, O_RDWR | O_CREAT, &ad) != 0) {
+ if (ad_open(&ad, to.p_path, ADFLAGS_HF, O_RDWR | O_CREAT) != 0) {
ERROR("Error opening adouble for: %s", to.p_path);
}
ad_setid( &ad, st.st_dev, st.st_ino, cnid, did, dvolume.db_stamp);
struct adouble ad;
ad_init(&ad, dvolume.volinfo.v_adouble, dvolume.volinfo.v_ad_options);
- if (ad_open_metadata(to, S_ISDIR(sb.st_mode) ? ADFLAGS_DIR : 0, O_RDWR, &ad) != 0) {
+ if (ad_open(&ad, to, S_ISDIR(sb.st_mode) ? (ADFLAGS_DIR | ADFLAGS_HF) : ADFLAGS_HF, O_RDWR) != 0) {
SLOG("Error opening adouble for: %s", to);
return 1;
}
+++ /dev/null
-Makefile
-Makefile.in
-adv1tov2
-.deps
-.libs
-.gitignore
-adv1tov2.o
+++ /dev/null
-# Makefile.am for bin/adv1tov2/
-
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
-bin_PROGRAMS = adv1tov2
-
-adv1tov2_SOURCES = adv1tov2.c
-adv1tov2_LDADD = $(top_builddir)/libatalk/libatalk.la
+++ /dev/null
-/*
- * $Id: adv1tov2.c,v 1.5 2009-10-14 01:38:28 didg Exp $
- * v1tov2: given a root directory, run down and convert all the
- * files/directories into appledouble v2.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <atalk/adouble.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <dirent.h>
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
-#include <ctype.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <errno.h>
-#include <string.h>
-
-#include <atalk/util.h>
-
-#if AD_VERSION == AD_VERSION2
-#if 0
-/* translate characters */
-static void xlate(char *name, int flags) {
- static const char hexdig[] = "0123456789abcdef";
- char upath[MAXPATHLEN + 1];
- char *m, *u;
- int doit = 0;
-
- m = name;
- u = upath;
- while (*m != '\0') {
- if (isascii(*m) && !isprint(*m)) {
- doit = 1;
- *u++ = ':';
- *u++ = hexdig[(*m & 0xf0) >> 4];
- *u++ = hexdig[*m & 0x0f];
- } else
- *u++ = *m;
- m++;
- }
-
- if (doit) {
- *u = '\0';
- rename(name, upath);
- if ((flags & ADFLAGS_DIR) == 0)
- rename(ad_path(name, flags), ad_path(upath, flags)); /* rename rfork */
- }
-}
-#endif
-
-/* ----------------------------- */
-char *fullpathname(const char *name)
-{
- static char wd[ MAXPATHLEN + 1];
-
- if ( getcwd( wd , MAXPATHLEN) ) {
- strlcat(wd, "/", MAXPATHLEN);
- strlcat(wd, name, MAXPATHLEN);
- }
- else {
- strlcpy(wd, name, MAXPATHLEN);
- }
- return wd;
-}
-
-#define MAXDESCEND 0xFFFF
-/* recursively descend subdirectories.
- * oh the stack space we use up! */
-static void descend(DIR *dp)
-{
- DIR *dpnew;
- struct dirent *de;
- struct stat st;
- struct adouble ad;
- int flags;
- static int count = 0;
-
- ad_init(&ad, AD_VERSION2, 0);
- if (count++ > MAXDESCEND) {
- fprintf(stderr, "FAILURE: too many subdirectories! possible infinite recursion.");
- return;
- }
-
- putc('(', stderr);
- for (de = readdir(dp); de; de = readdir(dp)) {
- if (de->d_name[0] == '.')
- continue;
-
- if (stat(de->d_name, &st) < 0) {
- fprintf(stderr, "FAILURE: can't stat %s\n", de->d_name);
- continue;
- }
-
- /* go down subdirectory */
- flags = ADFLAGS_HF;
- if (S_ISDIR(st.st_mode) && (dpnew = opendir(de->d_name))) {
- chdir(de->d_name);
- descend(dpnew);
- closedir(dpnew);
- chdir("..");
- flags |= ADFLAGS_DIR;
- }
-
- if (ad_open(de->d_name, flags, O_RDWR, 0, &ad) < 0) {
- if (errno != ENOENT)
- fprintf(stderr, "\nFAILURE: can't convert %s, %s\n", fullpathname(de->d_name), strerror(errno));
- continue;
- }
- ad_close(&ad, ADFLAGS_HF);
- fputc('.', stderr);
- }
- putc(')', stderr);
-}
-
-
-int main(int argc, char **argv)
-{
- DIR *dp;
- struct adouble ad;
-
- ad_init(&ad, AD_VERSION2, 0);
- if (argc != 2) {
- fprintf(stderr, "%s <directory>\n", *argv);
- return -1;
- }
-
- /* convert main directory */
- if (ad_open(argv[1], ADFLAGS_HF | ADFLAGS_DIR, O_RDWR, 0,
- &ad) < 0) {
- fprintf(stderr, "FAILURE: can't convert %s\n", argv[1]);
- return -1;
- }
-
- ad_close(&ad, ADFLAGS_HF);
- if ((dp = opendir(argv[1])) == NULL) {
- fprintf(stderr, "%s: unable to open %s\n", *argv, argv[1]);
- return -1;
- }
-
- chdir(argv[1]);
- descend(dp);
- closedir(dp);
- chdir("..");
-
- putc('\n', stderr);
- return 0;
-}
-
-#else /* AD_VERSION == AD_VERSION2 */
-int main(int argc, char **argv)
-{
- fprintf(stderr, "%s not built for v2 AppleDouble files.\n", *argv);
- return -1;
-}
-#endif /* AD_VERSION == AD_VERSION2 */
# Makefile.am for bin/megatron/
-INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
-
-bin_PROGRAMS = megatron
-
-megatron_SOURCES = asingle.c hqx.c macbin.c megatron.c nad.c updcrc.c
-megatron_LDADD = $(top_builddir)/libatalk/libatalk.la
-
-noinst_HEADERS = asingle.h megatron.h hqx.h macbin.h nad.h updcrc.h
-
-LINKS = unbin unhex unsingle hqx2bin single2bin macbinary binheader nadheader
-
-install-exec-hook:
- @for LINK in $(LINKS); do \
- rm -f $(DESTDIR)$(bindir)/$$LINK; \
- $(LN_S) megatron $(DESTDIR)$(bindir)/$$LINK; \
- done
-
-uninstall-hook:
- @for LINK in $(LINKS); do \
- rm -f $(DESTDIR)$(bindir)/$$LINK; \
- done
+# EXTRADIST = asingle.c hqx.c macbin.c megatron.c nad.c updcrc.c \
+# asingle.h megatron.h hqx.h macbin.h nad.h updcrc.h
AC_PROG_PERL
AC_PROG_GREP
AC_PROG_PS
-
AM_PROG_CC_C_O
dnl Checks for header files.
-AC_HEADER_DIRENT
AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(fcntl.h limits.h stdint.h strings.h time.h sys/param.h sys/fcntl.h sys/file.h sys/ioctl.h sys/time.h sys/mnttab.h sys/statvfs.h sys/stat.h sys/vfs.h mntent.h syslog.h unistd.h termios.h sys/termios.h netdb.h sgtty.h ufs/quota.h mount.h statfs.h sys/types.h dlfcn.h errno.h sys/errno.h sys/uio.h langinfo.h locale.h sys/filio.h)
NETATALK_WEBMIN
dnl --------------------- last minute substitutions
-
+dnl Request SUSv3 standard interfaces
+CFLAGS="$CFLAGS -D_XOPEN_SOURCE=600 -D__EXTENSIONS__"
AC_SUBST(LIBS)
AC_SUBST(CFLAGS)
AC_SUBST(OVERWRITE_CONFIG)
if ((c = getoption(buf, "-port")))
options->port = strdup(c);
+#ifndef NO_DDP
if ((c = getoption(buf, "-ddpaddr")))
atalk_aton(c, &options->ddpaddr);
+#endif
if ((c = getoption(buf, "-signature")) && (opt = strdup(c)))
options->signatureopt = opt;
/*
- * $Id: desktop.c,v 1.50.2.1 2010-02-01 10:56:08 franklahm Exp $
- *
* See COPYRIGHT.
*
* bug:
} else
adp = of->of_ad;
- if (ad_open_metadata( upath , ( (isadir) ? ADFLAGS_DIR : 0), O_CREAT, adp) < 0 ) {
+ if (ad_open(adp, upath,
+ ADFLAGS_HF | ( (isadir) ? ADFLAGS_DIR : 0),
+ O_CREAT | O_RDWR,
+ 0666) < 0 ) {
return( AFPERR_ACCESS );
}
memcpy( ad_entry( adp, ADEID_COMMENT ), ibuf, clen );
ad_flush( adp );
}
- ad_close_metadata( adp);
+ if (adp == &ad)
+ ad_close_metadata( adp);
return( AFP_OK );
}
} else
adp = of->of_ad;
- if ( ad_open_metadata( upath, (isadir) ? ADFLAGS_DIR : 0, 0, adp) < 0 ) {
+ if ( ad_open(adp, upath, ADFLAGS_HF | (isadir) ? ADFLAGS_DIR : 0, 0) < 0 ) {
switch ( errno ) {
case ENOENT :
return( AFPERR_NOITEM );
/* get_id needs adp for reading CNID from adouble file */
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ((ad_open_metadata(path->u_name, ADFLAGS_DIR, 0, &ad)) == 0) /* 1 */
+ if ((ad_open(&ad, path->u_name, ADFLAGS_HF | ADFLAGS_DIR)) == 0) /* 1 */
adp = &ad;
/* Get CNID */
(1 << DIRPBIT_FINFO)))) {
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ( !ad_metadata( upath, ADFLAGS_CREATE|ADFLAGS_DIR, &ad) ) {
+ if ( !ad_metadata( upath, ADFLAGS_DIR, &ad) )
isad = 1;
- if (ad.ad_md->adf_flags & O_CREAT) {
- /* We just created it */
- ad_setname(&ad, s_path->m_name);
- ad_setid( &ad,
- s_path->st.st_dev,
- s_path->st.st_ino,
- dir->d_did,
- dir->d_pdid,
- vol->v_stamp);
- ad_flush( &ad);
- }
- }
}
pdid = dir->d_pdid;
}
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (ad_open_metadata( upath, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
+ if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR, O_CREAT, 0777) != 0) {
/*
* Check to see what we're trying to set. If it's anything
* but ACCESS, UID, or GID, give an error. If it's any of those
}
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad ) < 0) {
+ if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR, O_CREAT, 0777) < 0) {
if (vol_noadouble(vol))
goto createdir_done;
return( AFPERR_ACCESS );
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (!ad_open_metadata( dst, ADFLAGS_DIR, 0, &ad)) {
+ if (ad_open(&ad, dst, ADFLAGS_HF | ADFLAGS_DIR) == 0) {
ad_setname(&ad, newname);
ad_flush( &ad);
ad_close_metadata( &ad);
/*
- $Id: extattrs.c,v 1.29 2010-01-05 12:06:33 franklahm Exp $
Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
This program is free software; you can redistribute it and/or modify
return( AFPERR_NOOBJ );
}
- adp = of_ad(vol, s_path, &ad);
uname = s_path->u_name;
/*
We have to check the FinderInfo for the file, because if they aren't all 0
if (S_ISDIR(st->st_mode))
adflags = ADFLAGS_DIR;
- if ( ad_metadata( uname, adflags, adp) < 0 ) {
+ adp = &ad;
+ ad_init(adp, vol->v_adouble, vol->v_ad_options);
+ if (ad_metadata(uname, adflags, adp) != 0 ) {
switch (errno) {
case ENOENT:
- adp = NULL;
break;
case EACCES:
LOG(log_error, logtype_afpd, "afp_listextattr(%s): %s: check resource fork permission?",
LOG(log_error, logtype_afpd, "afp_listextattr(%s): error getting metadata: %s", uname, strerror(errno));
return AFPERR_MISC;
}
- }
-
- if (adp) {
+ } else {
FinderInfo = ad_entry(adp, ADEID_FINDERI);
-#ifdef DEBUG
- LOG(log_maxdebug, logtype_afpd, "afp_listextattr(%s): FinderInfo:", uname);
- hexdump( FinderInfo, 32);
-#endif
-
if ((adflags & ADFLAGS_DIR)) {
/* set default view */
uint16 = htons(FINDERINFO_CLOSEDVIEW);
default:
buf_valid = 1;
}
- }
+ } /* if ((maxreply == 0) || (buf_valid == 0)) */
/* Start building reply packet */
bitmap = htons(bitmap);
exit:
if (ret != AFP_OK)
buf_valid = 0;
+
if (adp)
- ad_close_metadata( adp);
+ ad_close_metadata(adp);
return ret;
}
adp = of_ad(vol, path, &ad);
upath = path->u_name;
- if ( ad_metadata( upath, flags|ADFLAGS_CREATE, adp) < 0 ) {
+ if ( ad_metadata( upath, flags, adp) < 0 ) {
switch (errno) {
case EACCES:
LOG(log_error, logtype_afpd, "getfilparams(%s): %s: check resource fork permission?",
}
}
rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp);
- if ( adp ) {
+ if ( adp == &ad ) {
ad_close_metadata( adp);
}
/* ----------------------------- */
int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
- struct adouble ad, *adp;
+ struct adouble ad;
struct vol *vol;
struct dir *dir;
struct ofork *of = NULL;
memcpy(&vid, ibuf, sizeof( vid ));
ibuf += sizeof( vid );
- if (NULL == ( vol = getvolbyvid( vid )) ) {
+ if (NULL == ( vol = getvolbyvid( vid )) )
return( AFPERR_PARAM );
- }
if (vol->v_flags & AFPVOL_RO)
return AFPERR_VLOCK;
memcpy(&did, ibuf, sizeof( did));
ibuf += sizeof( did );
- if (NULL == ( dir = dirlookup( vol, did )) ) {
+ if (NULL == ( dir = dirlookup( vol, did )) )
return afp_errno;
- }
- if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
+ if (NULL == ( s_path = cname( vol, dir, &ibuf )) )
return get_afp_errno(AFPERR_PARAM);
- }
- if ( *s_path->m_name == '\0' ) {
+ if ( *s_path->m_name == '\0' )
return( AFPERR_BADTYPE );
- }
upath = s_path->u_name;
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options);
/* if upath is deleted we already in trouble anyway */
if ((of = of_findname(s_path))) {
- adp = of->of_ad;
- } else {
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- adp = &ad;
- }
- if ( creatf) {
- /* on a hard create, fail if file exists and is open */
- if (of)
+ if (creatf)
return AFPERR_BUSY;
+ else
+ return AFPERR_EXIST;
+ }
+
+ if ( creatf)
openf = O_RDWR|O_CREAT|O_TRUNC;
- } else {
+ else
/* on a soft create, if the file is open then ad_open won't fail
- because open syscall is not called
- */
- if (of) {
- return AFPERR_EXIST;
- }
+ because open syscall is not called */
openf = O_RDWR|O_CREAT|O_EXCL;
- }
- if ( ad_open( upath, ADFLAGS_DF|ADFLAGS_HF|ADFLAGS_NOHF|ADFLAGS_CREATE,
- openf, 0666, adp) < 0 ) {
+ if ( ad_open(&ad, upath, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF,
+ openf, 0666, openf, 0666) < 0 ) {
switch ( errno ) {
case EROFS:
return AFPERR_VLOCK;
return( AFPERR_PARAM );
}
}
- if ( ad_reso_fileno( adp ) == -1 ) { /* Hard META / HF */
+ if ( ad_meta_fileno( &ad ) == -1 ) { /* Hard META / HF */
/* on noadouble volumes, just creating the data fork is ok */
if (vol_noadouble(vol)) {
- ad_close( adp, ADFLAGS_DF );
+ ad_close( &ad, ADFLAGS_DF );
goto createfile_done;
}
/* FIXME with hard create on an existing file, we already
* corrupted the data file.
*/
netatalk_unlink( upath );
- ad_close( adp, ADFLAGS_DF );
+ ad_close( &ad, ADFLAGS_DF );
return AFPERR_ACCESS;
}
path = s_path->m_name;
- ad_setname(adp, path);
- ad_flush( adp);
- ad_close( adp, ADFLAGS_DF|ADFLAGS_HF );
+ ad_setname(&ad, path);
+ ad_flush(&ad);
+ ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF );
createfile_done:
curdir->offcnt++;
/* second try with adouble open
*/
- if ( ad_open_metadata( upath, 0, O_CREAT, adp) < 0) {
+ if ( ad_open(adp, upath, ADFLAGS_HF, O_RDWR | O_CREAT, 0666) < 0) {
LOG(log_debug, logtype_afpd, "setfilparams: ad_open_metadata error");
/*
* For some things, we don't need an adouble header:
if (isad) {
ad_flush( adp);
- ad_close_metadata( adp);
-
+ if (adp == &ad)
+ ad_close_metadata( adp);
}
if (change_parent_mdate && gettimeofday(&tv, NULL) == 0) {
/* don't care if we can't open the newly renamed ressource fork
*/
- if (!ad_open( dst, ADFLAGS_HF, O_RDWR, 0666, adp)) {
+ if (ad_open(adp, dst, ADFLAGS_HF, O_RDWR) == 0) {
ad_setname(adp, newname);
ad_flush( adp );
ad_close( adp, ADFLAGS_HF );
adp = of_ad(s_vol, s_path, &ad);
- if (ad_open(s_path->u_name , ADFLAGS_DF |ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+ if (ad_open(adp, s_path->u_name, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF, O_RDONLY, O_RDONLY) < 0) {
return AFPERR_DENYCONF;
}
denyreadset = (getforkmode(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
setvoltime(obj, d_vol );
copy_exit:
- ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
+ if (adp == &ad)
+ ad_close( adp, ADFLAGS_DF |ADFLAGS_HF );
return( retvalue );
}
adflags |= ADFLAGS_HF;
}
- if (ad_openat(sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY, 0, adp) < 0) {
+ if (ad_openat(adp, sfd, src, adflags | ADFLAGS_NOHF, O_RDONLY) < 0) {
ret_err = errno;
goto done;
}
}
ad_init(&add, d_vol->v_adouble, d_vol->v_ad_options);
- if (ad_open(dst , adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, &add) < 0) {
+ if (ad_open(&add, dst, adflags, O_RDWR|O_CREAT|O_EXCL, st.st_mode, O_RDWR|O_CREAT|O_EXCL, st.st_mode) < 0) {
ret_err = errno;
ad_close( adp, adflags );
if (EEXIST != ret_err) {
/* try to open both forks at once */
adflags = ADFLAGS_DF;
- if ( ad_openat(dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY, 0, &ad ) < 0 ) {
+ if ( ad_openat(&ad, dirfd, file, adflags |ADFLAGS_HF|ADFLAGS_NOHF, O_RDONLY) < 0 ) {
switch (errno) {
case ENOENT:
err = AFPERR_NOOBJ;
cnid_t did = param->did;
cnid_t aint;
- if ( lstat(de->d_name, &path.st)<0 )
+ if ( lstat(de->d_name, &path.st) < 0 )
return 0;
/* update or add to cnid */
aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */
-#if AD_VERSION > AD_VERSION1
- if (aint != CNID_INVALID && !S_ISDIR(path.st.st_mode)) {
- struct adouble ad, *adp;
-
- path.st_errno = 0;
- path.st_valid = 1;
- path.u_name = de->d_name;
-
- adp = of_ad(vol, &path, &ad);
-
- if ( ad_open_metadata( de->d_name, 0, 0, adp ) < 0 ) {
- return 0;
- }
- if (ad_setid(adp, path.st.st_dev, path.st.st_ino, aint, did, vol->v_stamp)) {
- ad_flush(adp);
- }
- ad_close_metadata(adp);
- }
-#endif /* AD_VERSION > AD_VERSION1 */
-
return 0;
}
adp = (*of)->of_ad;
}
else {
- ret = ad_open( path->u_name, ADFLAGS_HF, O_RDONLY, 0, adp);
+ ret = ad_open(adp, path->u_name, ADFLAGS_HF, O_RDONLY);
/* META and HF */
if ( !ret && ad_reso_fileno(adp) != -1 && !(adp->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
/* from AFP spec.
/*
- * $Id: fork.c,v 1.73 2010-03-30 12:55:26 franklahm Exp $
- *
* Copyright (c) 1990,1993 Regents of The University of Michigan.
+ * Copyright (c) 2010 Frank Lahm
+ *
* All Rights Reserved. See COPYRIGHT.
*/
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
-
#include <string.h>
#include <errno.h>
-
-#include <atalk/adouble.h>
-#include <atalk/logger.h>
-
#include <sys/param.h>
#include <sys/socket.h>
+#include <inttypes.h>
#include <netatalk/at.h>
-
#include <atalk/dsi.h>
#include <atalk/atp.h>
#include <atalk/asp.h>
#include <atalk/afp.h>
-
+#include <atalk/adouble.h>
+#include <atalk/logger.h>
#include <atalk/util.h>
#include <atalk/cnid.h>
+#include <atalk/bstradd.h>
#include "fork.h"
#include "file.h"
static int getforkparams(struct ofork *ofork, u_int16_t bitmap, char *buf, size_t *buflen)
{
struct path path;
- struct stat *st;
+ struct stat *st;
+
+ struct adouble *adp;
+ struct dir *dir;
+ struct vol *vol;
- struct adouble *adp;
- struct dir *dir;
- struct vol *vol;
-
/* can only get the length of the opened fork */
- if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
- && (ofork->of_flags & AFPFORK_RSRC))
- ||
- ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
- && (ofork->of_flags & AFPFORK_DATA))) {
+ if ( ( (bitmap & ((1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN)))
+ && (ofork->of_flags & AFPFORK_RSRC))
+ ||
+ ( (bitmap & ((1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN)))
+ && (ofork->of_flags & AFPFORK_DATA))) {
return( AFPERR_BITMAP );
}
path.m_name = of_name(ofork);
path.id = 0;
st = &path.st;
- if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
- (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
+ if ( bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) |
+ (1<<FILPBIT_FNUM) | (1 << FILPBIT_CDATE) |
(1 << FILPBIT_MDATE) | (1 << FILPBIT_BDATE))) {
if ( ad_data_fileno( ofork->of_ad ) <= 0 ) {
/* 0 is for symlink */
ret = ntohl(temp)| (ret << 32);
}
else {
- ret = (int)ret; /* sign extend */
+ ret = (int)ret; /* sign extend */
}
return ret;
}
return ret;
}
-/* ------------------------
-*/
+/* ------------------------
+ */
static int is_neg(int is64, off_t val)
{
if (val < 0 || (sizeof(off_t) == 8 && !is64 && (val & 0x80000000U)))
- return 1;
+ return 1;
return 0;
}
-static int sum_neg(int is64, off_t offset, off_t reqcount)
+static int sum_neg(int is64, off_t offset, off_t reqcount)
{
- if (is_neg(is64, offset +reqcount) )
- return 1;
+ if (is_neg(is64, offset +reqcount) )
+ return 1;
return 0;
}
/* -------------------------
-*/
+ */
static int setforkmode(struct adouble *adp, int eid, int ofrefnum, int what)
{
return ad_lock(adp, eid, ADLOCK_RD | ADLOCK_FILELOCK, what, 1, ofrefnum);
}
/* -------------------------
-*/
+ */
int getforkmode(struct adouble *adp, int eid, int what)
{
return ad_testlock(adp, eid, what);
}
/* -------------------------
-*/
+ */
static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
{
int ret;
if ((access & OPENACC_DRD) && readset) {
errno = EACCES;
return -1;
- }
+ }
/* boolean logic is not enough, because getforkmode is not always telling the
- * true
+ * true
*/
if ((access & OPENACC_RD)) {
ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_RD);
if ((access & OPENACC_DWR) && writeset) {
errno = EACCES;
return -1;
- }
+ }
if ((access & OPENACC_WR)) {
ret = setforkmode(adp, eid, ofrefnum, AD_FILELOCK_OPEN_WR);
if (ret)
/* ----------------------- */
int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
{
- struct vol *vol;
- struct dir *dir;
- struct ofork *ofork, *opened;
- struct adouble *adsame = NULL;
- size_t buflen;
- int ret, adflags, eid;
- u_int32_t did;
- u_int16_t vid, bitmap, access, ofrefnum;
- char fork, *path, *upath;
- struct stat *st;
- u_int16_t bshort;
- struct path *s_path;
-
+ struct vol *vol;
+ struct dir *dir;
+ struct ofork *ofork, *opened;
+ struct adouble *adsame = NULL;
+ size_t buflen;
+ int ret, adflags, eid;
+ uint32_t did;
+ uint16_t vid, bitmap, access, ofrefnum;
+ char fork, *path, *upath;
+ struct stat *st;
+ uint16_t bshort;
+ struct path *s_path;
+
ibuf++;
fork = *ibuf++;
memcpy(&vid, ibuf, sizeof( vid ));
ibuf += sizeof( int );
if (NULL == ( dir = dirlookup( vol, did ))) {
- return afp_errno;
+ return afp_errno;
}
memcpy(&bitmap, ibuf, sizeof( bitmap ));
}
if (NULL == ( s_path = cname( vol, dir, &ibuf ))) {
- return get_afp_errno(AFPERR_PARAM);
+ return get_afp_errno(AFPERR_PARAM);
}
if (*s_path->m_name == '\0') {
- /* it's a dir ! */
- return AFPERR_BADTYPE;
+ /* it's a dir ! */
+ return AFPERR_BADTYPE;
}
+ LOG(log_debug, logtype_afpd,
+ "afp_openfork(\"%s\", fork: %s)",
+ abspath(s_path->u_name),
+ (fork & OPENFORK_DATA) ? "d" : "r");
+
/* stat() data fork st is set because it's not a dir */
switch ( s_path->st_errno ) {
case 0:
if (check_access(upath, access ) < 0) {
return AFPERR_ACCESS;
}
- }
- else {
+ } else {
if (file_access(s_path, access ) < 0) {
return AFPERR_ACCESS;
}
/* XXX: this probably isn't the best way to do this. the already
open bits should really be set if the fork is opened by any
program, not just this one. however, that's problematic to do
- if we can't write lock files somewhere. opened is also passed to
+ if we can't write lock files somewhere. opened is also passed to
ad_open so that we can keep file locks together.
- FIXME: add the fork we are opening?
+ FIXME: add the fork we are opening?
*/
if ((opened = of_findname(s_path))) {
adsame = opened->of_ad;
if ( fork == OPENFORK_DATA ) {
eid = ADEID_DFORK;
- adflags = ADFLAGS_DF|ADFLAGS_HF;
+ adflags = ADFLAGS_DF | ADFLAGS_HF;
} else {
eid = ADEID_RFORK;
- adflags = ADFLAGS_HF;
+ adflags = ADFLAGS_RF | ADFLAGS_HF;
}
path = s_path->m_name;
ret = AFPERR_NOOBJ;
if (access & OPENACC_WR) {
/* try opening in read-write mode */
- if (ad_open(upath, adflags, O_RDWR, 0, ofork->of_ad) < 0) {
+ if (ad_open(ofork->of_ad, upath, adflags, O_RDWR, O_RDWR) < 0) {
switch ( errno ) {
case EROFS:
ret = AFPERR_VLOCK;
case ENOENT:
if (fork == OPENFORK_DATA) {
/* try to open only the data fork */
- if (ad_open(upath, ADFLAGS_DF, O_RDWR, 0, ofork->of_ad) < 0) {
+ if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDWR) < 0) {
goto openfork_err;
}
adflags = ADFLAGS_DF;
- }
- else {
+ } else {
/* here's the deal. we only try to create the resource
- * fork if the user wants to open it for write acess. */
- if (ad_open(upath, adflags, O_RDWR | O_CREAT, 0666, ofork->of_ad) < 0)
+ * fork if the user wants to open it for write acess. */
+ if (ad_open(ofork->of_ad, upath, adflags, O_RDWR | O_CREAT, 0666, O_RDWR | O_CREAT, 0666) < 0)
goto openfork_err;
ofork->of_flags |= AFPFORK_OPEN;
}
} else {
/* try opening in read-only mode */
ret = AFPERR_NOOBJ;
- if (ad_open(upath, adflags, O_RDONLY, 0, ofork->of_ad) < 0) {
+ if (ad_open(ofork->of_ad, upath, adflags, O_RDONLY, O_RDONLY) < 0) {
switch ( errno ) {
case EROFS:
ret = AFPERR_VLOCK;
case ENOENT:
/* see if client asked for a read only data fork */
if (fork == OPENFORK_DATA) {
- if (ad_open(upath, ADFLAGS_DF, O_RDONLY, 0, ofork->of_ad) < 0) {
+ if (ad_open(ofork->of_ad, upath, ADFLAGS_DF, O_RDONLY) < 0) {
goto openfork_err;
}
adflags = ADFLAGS_DF;
}
- /* else we don't set AFPFORK_OPEN because there's no ressource fork file
+ /* else we don't set AFPFORK_OPEN because there's no ressource fork file
* We need to check AFPFORK_OPEN in afp_closefork(). eg fork open read-only
* then create in open read-write.
* FIXME , it doesn't play well with byte locking example:
* ressource fork open read only
* locking set on it (no effect, there's no file!)
* ressource fork open read write now
- */
+ */
break;
case EMFILE :
case ENFILE :
goto openfork_err;
break;
default:
- LOG(log_error, logtype_afpd, "afp_openfork('%s/%s'): ad_open: errno: %i (%s)",
- getcwdpath, s_path->m_name, errno, strerror(errno) );
+ LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s",
+ abspath(s_path->m_name), strerror(errno) );
goto openfork_err;
break;
}
rbuf += sizeof( u_int16_t );
/* check WriteInhibit bit if we have a ressource fork
- * the test is done here, after some Mac trafic capture
+ * the test is done here, after some Mac trafic capture
*/
if (ad_meta_fileno(ofork->of_ad) != -1) { /* META */
ad_getattr(ofork->of_ad, &bshort);
int afp_setforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen, char *rbuf _U_, size_t *rbuflen)
{
- struct ofork *ofork;
- off_t size;
- u_int16_t ofrefnum, bitmap;
+ struct ofork *ofork;
+ off_t size;
+ u_int16_t ofrefnum, bitmap;
int err;
int is64;
int eid;
- off_t st_size;
-
+ off_t st_size;
+
ibuf += 2;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
} else
return AFPERR_PARAM;
- if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
- && eid == ADEID_RFORK
- ) ||
- ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
- && eid == ADEID_DFORK)) {
+ if ( ( (bitmap & ( (1<<FILPBIT_DFLEN) | (1<<FILPBIT_EXTDFLEN) ))
+ && eid == ADEID_RFORK
+ ) ||
+ ( (bitmap & ( (1<<FILPBIT_RFLEN) | (1<<FILPBIT_EXTRFLEN) ))
+ && eid == ADEID_DFORK)) {
return AFPERR_BITMAP;
}
-
+
is64 = 0;
if ((bitmap & ( (1<<FILPBIT_EXTDFLEN) | (1<<FILPBIT_EXTRFLEN) ))) {
if (afp_version >= 30) {
is64 = 4;
}
- else
- return AFPERR_BITMAP;
+ else
+ return AFPERR_BITMAP;
}
if (ibuflen < 2+ sizeof(ofrefnum) + sizeof(bitmap) + is64 +4)
return AFPERR_PARAM ;
-
+
size = get_off_t(&ibuf, is64);
if (size < 0)
if (bitmap == (1<<FILPBIT_DFLEN) || bitmap == (1<<FILPBIT_EXTDFLEN)) {
- st_size = ad_size(ofork->of_ad, eid);
- err = -2;
- if (st_size > size &&
- ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
+ st_size = ad_size(ofork->of_ad, eid);
+ err = -2;
+ if (st_size > size &&
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0)
goto afp_setfork_err;
err = ad_dtruncate( ofork->of_ad, size );
if (st_size > size)
- ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
if (err < 0)
goto afp_setfork_err;
} else if (bitmap == (1<<FILPBIT_RFLEN) || bitmap == (1<<FILPBIT_EXTRFLEN)) {
ad_refresh( ofork->of_ad );
- st_size = ad_size(ofork->of_ad, eid);
- err = -2;
- if (st_size > size &&
- ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
+ st_size = ad_size(ofork->of_ad, eid);
+ err = -2;
+ if (st_size > size &&
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, size, st_size -size, ofork->of_refnum) < 0) {
goto afp_setfork_err;
- }
+ }
err = ad_rtruncate(ofork->of_ad, size);
if (st_size > size)
- ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum);
if (err < 0)
goto afp_setfork_err;
* read and write. that's most easily handled by always doing an
* appropriate check before each ad_read/ad_write. other things
* that can change files like truncate are handled internally to those
- * functions.
+ * functions.
*/
#define ENDBIT(a) ((a) & 0x80)
#define UNLOCKBIT(a) ((a) & 0x01)
/* ---------------------- */
static int byte_lock(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
{
- struct ofork *ofork;
+ struct ofork *ofork;
off_t offset, length;
int eid;
- u_int16_t ofrefnum;
+ u_int16_t ofrefnum;
u_int8_t flags;
int lockop;
-
+
*rbuflen = 0;
/* figure out parameters */
/* FIXME AD_FILELOCK test is surely wrong */
if (length == -1)
length = BYTELOCK_MAX;
- else if (!length || is_neg(is64, length)) {
- return AFPERR_PARAM;
- } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
+ else if (!length || is_neg(is64, length)) {
+ return AFPERR_PARAM;
+ } else if ((length >= AD_FILELOCK_BASE) && -1 == (ad_reso_fileno(ofork->of_ad))) { /* HF ?*/
return AFPERR_LOCK;
}
if (ENDBIT(flags)) {
offset += ad_size(ofork->of_ad, eid);
- /* FIXME what do we do if file size > 2 GB and
+ /* FIXME what do we do if file size > 2 GB and
it's not byte_lock_ext?
*/
}
/* --------------------------- */
int afp_bytelock(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
{
- return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
+ return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 0);
}
/* --------------------------- */
int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
{
- return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
+ return byte_lock ( obj, ibuf, ibuflen, rbuf, rbuflen , 1);
}
#undef UNLOCKBIT
/* --------------------------- */
static int crlf(struct ofork *of)
{
- struct extmap *em;
+ struct extmap *em;
if ( ad_meta_fileno( of->of_ad ) == -1 || !memcmp( ufinderi, ad_entry( of->of_ad, ADEID_FINDERI),8)) { /* META */
/* no resource fork or no finderinfo, use our files extension mapping */
if (!( em = getextmap( of_name(of) )) || memcmp( "TEXT", em->em_type, sizeof( em->em_type ))) {
return 0;
- }
+ }
/* file type is TEXT */
return 1;
static ssize_t read_file(struct ofork *ofork, int eid,
- off_t offset, u_char nlmask,
- u_char nlchar, char *rbuf,
- size_t *rbuflen, const int xlate)
+ off_t offset, u_char nlmask,
+ u_char nlchar, char *rbuf,
+ size_t *rbuflen, const int xlate)
{
ssize_t cc;
int eof = 0;
}
/* -----------------------------
- * with ddp, afp_read can return fewer bytes than in reqcount
+ * with ddp, afp_read can return fewer bytes than in reqcount
* so return EOF only if read actually past end of file not
* if offset +reqcount > size of file
* e.g.:
* read fork offset 0 size 10752 ???? ==> 4264 bytes (without EOF)
* read fork offset 4264 size 6128 ==> 4264 (without EOF)
* read fork offset 9248 size 1508 ==> 1182 (EOF)
- * 10752 is a bug in Mac 7.5.x finder
+ * 10752 is a bug in Mac 7.5.x finder
*
- * with dsi, should we check that reqcount < server quantum?
-*/
+ * with dsi, should we check that reqcount < server quantum?
+ */
static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
{
- struct ofork *ofork;
- off_t offset, saveoff, reqcount, savereqcount;
- ssize_t cc, err;
- int eid, xlate = 0;
- u_int16_t ofrefnum;
- u_char nlmask, nlchar;
-
+ struct ofork *ofork;
+ off_t offset, saveoff, reqcount, savereqcount;
+ ssize_t cc, err;
+ int eid, xlate = 0;
+ u_int16_t ofrefnum;
+ u_char nlmask, nlchar;
+
ibuf += 2;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
ibuf += sizeof( u_short );
offset = get_off_t(&ibuf, is64);
reqcount = get_off_t(&ibuf, is64);
+ LOG(log_debug, logtype_afpd,
+ "afp_read(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
if (is64) {
nlmask = nlchar = 0;
}
goto afp_read_err;
}
-#define min(a,b) ((a)<(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
*rbuflen = min( reqcount, *rbuflen );
err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate);
if (err < 0)
/* subtract off the offset */
size -= offset;
if (reqcount > size) {
- reqcount = size;
- err = AFPERR_EOF;
+ reqcount = size;
+ err = AFPERR_EOF;
}
offset += *rbuflen;
*rbuflen = cc;
/* due to the nature of afp packets, we have to exit if we get
an error. we can't do this with translation on. */
-#ifdef WITH_SENDFILE
+#ifdef WITH_SENDFILE
if (!(xlate || Debug(obj) )) {
int fd;
-
+
fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0);
if (dsi_stream_read_file(dsi, fd, offset, dsi->datasize) < 0) {
if (errno == EINVAL || errno == ENOSYS)
goto afp_read_done;
}
-afp_read_loop:
-#endif
+ afp_read_loop:
+#endif
/* fill up our buffer. */
while (*rbuflen > 0) {
dsi_readdone(dsi);
goto afp_read_done;
-afp_read_exit:
+ afp_read_exit:
LOG(log_error, logtype_afpd, "afp_read(%s): %s", of_name(ofork), strerror(errno));
dsi_readdone(dsi);
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount,ofork->of_refnum);
return( AFP_OK );
}
-int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
+int afp_flushfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
- struct ofork *ofork;
- u_int16_t ofrefnum;
+ struct ofork *ofork;
+ u_int16_t ofrefnum;
*rbuflen = 0;
ibuf += 2;
return( AFPERR_PARAM );
}
+ LOG(log_debug, logtype_afpd,
+ "afp_flushfork(\"%s\", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath),
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
if ( flushfork( ofork ) < 0 ) {
LOG(log_error, logtype_afpd, "afp_flushfork(%s): %s", of_name(ofork), strerror(errno) );
}
There is a lot to tell about fsync, fdatasync, F_FULLFSYNC.
fsync(2) on OSX is implemented differently than on other platforms.
see: http://mirror.linux.org.au/pub/linux.conf.au/2007/video/talks/278.pdf.
- */
+*/
int afp_syncfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
struct ofork *ofork;
return( AFPERR_PARAM );
}
+ LOG(log_debug, logtype_afpd,
+ "afp_syncfork(\"%s\", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath),
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
if ( flushfork( ofork ) < 0 ) {
- LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
- return AFPERR_MISC;
+ LOG(log_error, logtype_afpd, "flushfork(%s): %s", of_name(ofork), strerror(errno) );
+ return AFPERR_MISC;
}
return( AFP_OK );
int err = 0, doflush = 0;
if ( ad_data_fileno( ofork->of_ad ) != -1 &&
- fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
+ fsync( ad_data_fileno( ofork->of_ad )) < 0 ) {
LOG(log_error, logtype_afpd, "flushfork(%s): dfile(%d) %s",
of_name(ofork), ad_data_fileno(ofork->of_ad), strerror(errno) );
err = -1;
}
if ( ad_reso_fileno( ofork->of_ad ) != -1 && /* HF */
- (ofork->of_flags & AFPFORK_RSRC)) {
+ (ofork->of_flags & AFPFORK_RSRC)) {
/* read in the rfork length */
ad_refresh(ofork->of_ad);
/* flush the header */
if (doflush && ad_flush(ofork->of_ad) < 0)
- err = -1;
+ err = -1;
if (fsync( ad_reso_fileno( ofork->of_ad )) < 0)
err = -1;
int afp_closefork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
- struct ofork *ofork;
- u_int16_t ofrefnum;
+ struct ofork *ofork;
+ u_int16_t ofrefnum;
*rbuflen = 0;
ibuf += 2;
LOG(log_error, logtype_afpd, "afp_closefork: of_find(%d) could not locate fork", ofrefnum );
return( AFPERR_PARAM );
}
+
+ LOG(log_debug, logtype_afpd,
+ "afp_closefork(\"%s\", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath),
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
if ( of_closefork( ofork ) < 0 ) {
LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) );
return( AFPERR_PARAM );
static ssize_t write_file(struct ofork *ofork, int eid,
- off_t offset, char *rbuf,
- size_t rbuflen, const int xlate)
+ off_t offset, char *rbuf,
+ size_t rbuflen, const int xlate)
{
char *p, *q;
ssize_t cc;
/* FPWrite. NOTE: on an error, we always use afp_write_err as
- * the client may have sent us a bunch of data that's not reflected
+ * the client may have sent us a bunch of data that's not reflected
* in reqcount et al. */
static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen, int is64)
{
- struct ofork *ofork;
- off_t offset, saveoff, reqcount;
- int endflag, eid, xlate = 0, err = AFP_OK;
- u_int16_t ofrefnum;
+ struct ofork *ofork;
+ off_t offset, saveoff, reqcount;
+ int endflag, eid, xlate = 0, err = AFP_OK;
+ u_int16_t ofrefnum;
ssize_t cc;
/* figure out parameters */
goto afp_write_err;
}
+ LOG(log_debug, logtype_afpd,
+ "afp_write(\"%s\", off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)",
+ cfrombstr(ofork->of_ad->ad_fullpath), offset, reqcount,
+ (ofork->of_flags & AFPFORK_DATA) ? "d" : "r");
+
if ((ofork->of_flags & AFPFORK_ACCWR) == 0) {
err = AFPERR_ACCESS;
goto afp_write_err;
/* offset can overflow on 64-bit capable filesystems.
* report disk full if that's going to happen. */
- if (sum_neg(is64, offset, reqcount)) {
+ if (sum_neg(is64, offset, reqcount)) {
err = AFPERR_DFULL;
goto afp_write_err;
}
#endif /* no afp/asp */
case AFPPROTO_DSI:
- {
- DSI *dsi = obj->handle;
+ {
+ DSI *dsi = obj->handle;
+
+ /* find out what we have already and write it out. */
+ cc = dsi_writeinit(dsi, rbuf, *rbuflen);
+ if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+ dsi_writeflush(dsi);
+ *rbuflen = 0;
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
+ return cc;
+ }
+ offset += cc;
- /* find out what we have already and write it out. */
- cc = dsi_writeinit(dsi, rbuf, *rbuflen);
- if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+#if 0 /*def HAVE_SENDFILE_WRITE*/
+ if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
+ if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
+ offset, dsi->datasize)) < 0) {
+ switch (errno) {
+ case EDQUOT :
+ case EFBIG :
+ case ENOSPC :
+ cc = AFPERR_DFULL;
+ break;
+ default :
+ LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
+ goto afp_write_loop;
+ }
dsi_writeflush(dsi);
*rbuflen = 0;
- ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
+ reqcount, ofork->of_refnum);
return cc;
}
- offset += cc;
-
-#if 0 /*def HAVE_SENDFILE_WRITE*/
- if (!(xlate || obj->options.flags & OPTION_DEBUG)) {
- if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket,
- offset, dsi->datasize)) < 0) {
- switch (errno) {
- case EDQUOT :
- case EFBIG :
- case ENOSPC :
- cc = AFPERR_DFULL;
- break;
- default :
- LOG(log_error, logtype_afpd, "afp_write: ad_writefile: %s", strerror(errno) );
- goto afp_write_loop;
- }
- dsi_writeflush(dsi);
- *rbuflen = 0;
- ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
- reqcount, ofork->of_refnum);
- return cc;
- }
- offset += cc;
- goto afp_write_done;
- }
+ offset += cc;
+ goto afp_write_done;
+ }
#endif /* 0, was HAVE_SENDFILE_WRITE */
- /* loop until everything gets written. currently
- * dsi_write handles the end case by itself. */
- while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
- if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
- dsi_writeflush(dsi);
- *rbuflen = 0;
- ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
- reqcount, ofork->of_refnum);
- return cc;
- }
- offset += cc;
+ /* loop until everything gets written. currently
+ * dsi_write handles the end case by itself. */
+ while ((cc = dsi_write(dsi, rbuf, *rbuflen))) {
+ if ((cc = write_file(ofork, eid, offset, rbuf, cc, xlate)) < 0) {
+ dsi_writeflush(dsi);
+ *rbuflen = 0;
+ ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff,
+ reqcount, ofork->of_refnum);
+ return cc;
}
+ offset += cc;
}
- break;
+ }
+ break;
}
ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum);
return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 0);
}
-/* ----------------------------
+/* ----------------------------
* FIXME need to deal with SIGXFSZ signal
-*/
+ */
int afp_write_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
{
return write_fork(obj, ibuf, ibuflen, rbuf, rbuflen, 1);
/* ---------------------------- */
int afp_getforkparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
{
- struct ofork *ofork;
+ struct ofork *ofork;
int ret;
- u_int16_t ofrefnum, bitmap;
+ u_int16_t ofrefnum, bitmap;
size_t buflen;
ibuf += 2;
memcpy(&ofrefnum, ibuf, sizeof( ofrefnum ));
}
if (AFP_OK != ( ret = getforkparams( ofork, bitmap,
- rbuf + sizeof( u_short ), &buflen ))) {
+ rbuf + sizeof( u_short ), &buflen ))) {
return( ret );
}
/*
- * $Id: ofork.c,v 1.32 2010/03/12 15:16:49 franklahm Exp $
- *
* Copyright (c) 1996 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*/
return NULL;
}
strlcpy( ad->ad_m_name, path, ad->ad_m_namelen);
- } else {
- /* Increase the refcount on this struct adouble. This is
- decremented again in oforc_dealloc. */
- ad->ad_refcount++;
}
of->of_ad = ad;
of_unhash(of);
oforks[ of->of_refnum % nforks ] = NULL;
-
- /* decrease refcount */
- of->of_ad->ad_refcount--;
-
- if ( of->of_ad->ad_refcount <= 0) {
- free( of->of_ad->ad_m_name );
- free( of->of_ad);
- } else {/* someone's still using it. just free this user's locks */
- ad_unlock(of->of_ad, of->of_refnum);
- }
+ ad_unlock(of->of_ad, of->of_refnum);
free( of );
}
#include <atalk/asp.h>
#include <atalk/nbp.h>
#include <atalk/unicode.h>
+#include <atalk/util.h>
#include "globals.h" /* includes <netdb.h> */
#include "status.h"
/* extract the obj part of the server */
Obj = (char *) server;
+#ifndef NO_DDP
nbp_name(server, &Obj, &Type, &Zone);
+#endif
if ((size_t)-1 == (len = convert_string(
- options->unixcharset, options->maccharset,
- Obj, -1, buf, sizeof(buf))) ) {
- len = MIN(strlen(Obj), 31);
+ options->unixcharset, options->maccharset,
+ Obj, -1, buf, sizeof(buf))) ) {
+ len = MIN(strlen(Obj), 31);
*data++ = len;
memcpy( data, Obj, len );
- LOG ( log_error, logtype_afpd, "Could not set servername, using fallback");
+ LOG ( log_error, logtype_afpd, "Could not set servername, using fallback");
} else {
*data++ = len;
memcpy( data, buf, len );
/* extract the obj part of the server */
Obj = (char *) (options->server ? options->server : options->hostname);
+#ifndef NO_DDP
nbp_name(options->server ? options->server : options->hostname, &Obj, &Type, &Zone);
-
+#endif
if ((size_t) -1 == (len = convert_string (
- options->unixcharset, CH_UTF8_MAC,
- Obj, -1, data+sizeof(namelen), maxstatuslen-offset )) ) {
- LOG ( log_error, logtype_afpd, "Could not set utf8 servername");
+ options->unixcharset, CH_UTF8_MAC,
+ Obj, -1, data+sizeof(namelen), maxstatuslen-offset )) ) {
+ LOG ( log_error, logtype_afpd, "Could not set utf8 servername");
- /* set offset to 0 */
- memset(begin + *nameoffset, 0, sizeof(offset));
+ /* set offset to 0 */
+ memset(begin + *nameoffset, 0, sizeof(offset));
data = begin + offset;
- }
- else {
+ } else {
namelen = htons(len);
memcpy( data, &namelen, sizeof(namelen));
data += sizeof(namelen);
memcpy(begin + *nameoffset, &offset, sizeof(u_int16_t));
/* Now set the flag ... */
- memcpy(&status, begin + AFPSTATUS_FLAGOFF, sizeof(status));
- status = ntohs(status);
- status |= AFPSRVRINFO_SRVUTF8;
- status = htons(status);
- memcpy(begin + AFPSTATUS_FLAGOFF, &status, sizeof(status));
+ memcpy(&status, begin + AFPSTATUS_FLAGOFF, sizeof(status));
+ status = ntohs(status);
+ status |= AFPSRVRINFO_SRVUTF8;
+ status = htons(status);
+ memcpy(begin + AFPSTATUS_FLAGOFF, &status, sizeof(status));
}
/* return length of buffer */
switch (what) {
case UAM_OPTION_USERNAME:
- *buf = obj->username;
+ *buf = &(obj->username[0]);
if (len)
*len = sizeof(obj->username) - 1;
break;
if (!obj)
return AFPERR_PARAM;
+#ifndef NO_DDP
switch (obj->proto) {
case AFPPROTO_ASP:
if ((len = asp_wrtcont(obj->handle, buf, buflen )) < 0)
break;
case AFPPROTO_DSI:
+#endif
len = dsi_writeinit(obj->handle, buf, *buflen);
if (!len || ((len = action(handle, buf, len)) < 0)) {
dsi_writeflush(obj->handle);
goto uam_afp_read_err;
}
}
+#ifndef NO_DDP
break;
}
+#endif
return 0;
uam_afp_read_err:
struct dirent *dirp;
DIR *dir;
mode_t hf_mode;
- int osx = vol->v_adouble == AD_VERSION2_OSX;
int dropbox = (vol->v_flags & AFPVOL_DROPBOX);
mode |= vol->v_dperm;
for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
/* FIXME */
- if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
+ if (*dirp->d_name == '.') {
continue;
}
if ( lstat( dirp->d_name, &st ) < 0 ) {
}
if (!S_ISDIR(st.st_mode)) {
- int setmode = (osx && *dirp->d_name == '.')?hf_mode:mode;
-
- if (setfilmode(dirp->d_name, setmode, &st, vol->v_umask) < 0) {
+ if (setfilmode(dirp->d_name, mode, &st, vol->v_umask) < 0) {
LOG(log_error, logtype_afpd, "setdirmode: chmod %s: %s",dirp->d_name, strerror(errno) );
return -1;
}
struct stat st;
struct dirent *dirp;
DIR *dir;
- int osx = vol->v_adouble == AD_VERSION2_OSX;
if (( dir = opendir( name )) == NULL ) {
return( -1 );
}
for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
- if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) {
+ if ( *dirp->d_name == '.') {
continue;
}
if ( lstat( dirp->d_name, &st ) < 0 ) {
#include <atalk/logger.h>
#include <atalk/vfs.h>
#include <atalk/uuid.h>
+#include <atalk/ea.h>
#ifdef CNID_DB
#include <atalk/cnid.h>
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}};
/* Forward declarations */
else if (strcasecmp(val + 1, "xlateupper") == 0)
options[VOLOPT_CASEFOLD].i_value = AFPVOL_ULOWERMUPPER;
} else if (optionok(tmp, "adouble:", val)) {
- if (strcasecmp(val + 1, "v1") == 0)
- options[VOLOPT_ADOUBLE].i_value = AD_VERSION1;
-#if AD_VERSION == AD_VERSION2
- else if (strcasecmp(val + 1, "v2") == 0)
+ 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;
- else if (strcasecmp(val + 1, "sfm") == 0)
- options[VOLOPT_ADOUBLE].i_value = AD_VERSION1_SFM;
-#endif
+ else if (strcasecmp(val + 1, "ea") == 0)
+ options[VOLOPT_ADOUBLE].i_value = AD_VERSION_EA;
} else if (optionok(tmp, "options:", val)) {
char *p;
* .Parent file here if it doesn't exist. */
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ( ad_open_metadata( vol->v_path, ADFLAGS_DIR, O_CREAT, &ad) < 0 ) {
+ if (ad_open(&ad, vol->v_path, ADFLAGS_HF | ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0 ) {
isad = 0;
vol->v_ctime = AD_DATE_FROM_UNIX(st->st_mtime);
return AFPERR_BITMAP;
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 ( ad_open(&ad, vol->v_path, ADFLAGS_HF|ADFLAGS_DIR, O_RDWR) < 0 ) {
if (errno == EROFS)
return AFPERR_VLOCK;
if ( !ret && folder->hide) {
/* Hide it */
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (ad_open_metadata( p, ADFLAGS_DIR, O_CREAT, &ad) < 0) {
- free (p);
+ if (ad_open(&ad, p, ADFLAGS_DIR, O_RDWR | O_CREAT, 0666) != 0) {
+ free(p);
free(q);
return (-1);
}
*/
static int check_adfile(const char *fname, const struct stat *st)
{
- int ret, adflags;
+ int ret;
+ int adflags = ADFLAGS_HF;
struct adouble ad;
- char *adname;
+ const char *adname;
if (dbd_flags & DBD_FLAGS_CLEANUP)
return 0;
if (S_ISREG(st->st_mode))
- adflags = 0;
- else
- adflags = ADFLAGS_DIR;
+ adflags |= ADFLAGS_DIR;
adname = myvolinfo->ad_path(fname, adflags);
/* Create ad file */
ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
- if ((ret = ad_open_metadata( fname, adflags, O_CREAT, &ad)) != 0) {
+ if ((ret = ad_open(&ad, fname, adflags, O_CREAT | O_RDWR, 0666)) != 0) {
dbd_log( LOGSTD, "Error creating AppleDouble file '%s/%s': %s",
cwdbuf, adname, strerror(errno));
#endif
} else {
ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
- if (ad_open_metadata( fname, adflags, O_RDONLY, &ad) != 0) {
+ if (ad_open(&ad, fname, adflags, O_RDONLY) != 0) {
dbd_log( LOGSTD, "Error opening AppleDouble file for '%s/%s'", cwdbuf, fname);
return -1;
}
/* Create ad dir and set name */
ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
- if (ad_open_metadata( ".", ADFLAGS_DIR, O_CREAT, &ad) != 0) {
+ if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR, O_CREAT | O_RDWR, 0777) != 0) {
dbd_log( LOGSTD, "Error creating AppleDouble dir in %s: %s", cwdbuf, strerror(errno));
return -1;
}
ad_cnid = 0;
if ( (myvolinfo->v_flags & AFPVOL_CACHE) && ADFILE_OK) {
ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
- if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+ if (ad_open(&ad, name, adflags, O_RDWR) != 0) {
if (dbd_flags & DBD_FLAGS_CLEANUP)
return 0;
dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
cwdbuf, name, ntohl(db_cnid));
ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
- if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+ if (ad_open(&ad, name, adflags, O_RDWR) != 0) {
dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
cwdbuf, name, strerror(errno));
return 0;
dbd_log(LOGSTD, "Writing CNID data for '%s/%s' to AppleDouble file",
cwdbuf, name, ntohl(db_cnid));
ad_init(&ad, myvolinfo->v_adouble, myvolinfo->v_ad_options);
- if (ad_open_metadata( name, adflags, O_RDWR, &ad) != 0) {
+ if (ad_open(&ad, name, adflags, O_RDWR) != 0) {
dbd_log(LOGSTD, "Error opening AppleDouble file for '%s/%s': %s",
cwdbuf, name, strerror(errno));
return 0;
return -1;
}
- nametmp = rqst->name;
+ nametmp = (char *)rqst->name;
if ((b = readt(cur_fd, rqst, sizeof(struct cnid_dbd_rqst), 1, CNID_DBD_TIMEOUT))
!= sizeof(struct cnid_dbd_rqst)) {
if (b)
return 0;
}
rqst->name = nametmp;
- if (rqst->namelen && readt(cur_fd, rqst->name, rqst->namelen, 1, CNID_DBD_TIMEOUT)
+ if (rqst->namelen && readt(cur_fd, (char *)rqst->name, rqst->namelen, 1, CNID_DBD_TIMEOUT)
!= rqst->namelen) {
LOG(log_error, logtype_cnid, "error reading message name: %s", strerror(errno));
invalidate_fd(cur_fd);
}
/* We set this to make life easier for logging. None of the other stuff
needs zero terminated strings. */
- rqst->name[rqst->namelen] = '\0';
+ ((char *)(rqst->name))[rqst->namelen] = '\0';
LOG(log_maxdebug, logtype_cnid, "comm_rcv: got %u bytes", b + rqst->namelen);
rply->name = resbuf;
rply->namelen = 0;
- key.data = rqst->name;
+ key.data = (char *)rqst->name;
key.size = rqst->namelen;
if ((results = dbif_search(dbd, &key, resbuf)) < 0) {
char *rbuf, size_t *rbuflen)
{
char *username;
- int len, ulen;
+ int len;
+ size_t ulen;
u_int16_t temp16;
*rbuflen = 0;
/*
- * $Id: adouble.h,v 1.55 2010-03-30 12:55:26 franklahm Exp $
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*
#include <config.h>
#endif
-/* -------------------
- * need pread() and pwrite()
- */
-#ifdef HAVE_PREAD
-
-#ifndef HAVE_PWRITE
-#undef HAVE_PREAD
-#endif
-
-#endif
-
-#ifdef HAVE_PWRITE
-#ifndef HAVE_PREAD
-#undef HAVE_PWRITE
-#endif
-#endif
-
-/*
- Still have to figure out which platforms really
- need _XOPEN_SOURCE defined for pread.
-*/
-#if defined(HAVE_PREAD) && !defined(SOLARIS) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(TRU64)
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 500
-#endif
-#endif
-
+#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
-
-#ifdef HAVE_UNISTD_H
-#undef __USE_MISC
-#define __USE_MISC
#include <unistd.h>
-#endif
-
#include <sys/cdefs.h>
-
-#ifdef HAVE_FCNTL_H
#include <fcntl.h>
-#endif
-
#include <sys/mman.h>
-#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
-#endif
+
#include <netatalk/endian.h>
+#include <atalk/bstrlib.h>
/* version info */
-#define AD_VERSION1 0x00010000
-#define SFM_VERSION AD_VERSION1
-
#define AD_VERSION2 0x00020000
-#define AD_VERSION2_OSX 0x00020001
-/*
- #define AD_VERSION1_ADS 0x00010002
-*/
-#define AD_VERSION1_SFM 0x00010003
+#define AD_VERSION_EA 0x00020002
+
+/* default */
#define AD_VERSION AD_VERSION2
/*
*/
#define ADEID_DFORK 1
#define ADEID_RFORK 2
-#define ADEID_NAME 3 /* Note: starting with Netatalk 2.1 we do NOT alway set the name */
+#define ADEID_NAME 3
#define ADEID_COMMENT 4
#define ADEID_ICONBW 5
#define ADEID_ICONCOL 6
#define ADEID_AFPFILEI 14 /* where the rest of the FILEI info goes */
#define ADEID_DID 15
-#if AD_VERSION == AD_VERSION1
-#define ADEID_MAX 16
-#else
/* netatalk private note fileid reused DID */
#define ADEID_PRIVDEV 16
#define ADEID_PRIVINO 17
#define ADEID_PRIVSYN 18 /* in synch with database */
#define ADEID_PRIVID 19
-#define ADEID_SFMRESERVE1 20
-#define ADEID_SFMRESERVE2 21
+#define ADEID_MAX (ADEID_PRIVID + 1)
+/* These are the real ids for these entries, as stored in the adouble file */
#define AD_DEV 0x80444556
#define AD_INO 0x80494E4F
#define AD_SYN 0x8053594E
#define AD_ID 0x8053567E
-#define ADEID_MAX 22
-#endif
/* magic */
#define AD_APPLESINGLE_MAGIC 0x00051600
#define AD_APPLEDOUBLE_MAGIC 0x00051607
#define AD_MAGIC AD_APPLEDOUBLE_MAGIC
-#define SFM_MAGIC 0x00504641
/* sizes of relevant entry bits */
#define ADEDLEN_MAGIC 4
#define ADEDLEN_VERSION 4
#define ADEDLEN_FILLER 16
#define ADEDLEN_NENTRIES 2
-
-/* 26 */
-#define AD_HEADER_LEN (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
- ADEDLEN_FILLER + ADEDLEN_NENTRIES)
+#define AD_HEADER_LEN (ADEDLEN_MAGIC + ADEDLEN_VERSION + ADEDLEN_FILLER + ADEDLEN_NENTRIES)
#define AD_ENTRY_LEN 12 /* size of a single entry header */
-/* v1 field widths */
-#define ADEDLEN_NAME 255
-#define ADEDLEN_COMMENT 200
-#define ADEDLEN_FILEI 16
-#define ADEDLEN_FINDERI 32
-
-/* v2 field widths */
+/* field widths */
+#define ADEDLEN_NAME 255
+#define ADEDLEN_COMMENT 200
+#define ADEDLEN_FILEI 16
+#define ADEDLEN_FINDERI 32
#define ADEDLEN_FILEDATESI 16
#define ADEDLEN_SHORTNAME 12 /* length up to 8.3 */
#define ADEDLEN_AFPFILEI 4
#define ADEDLEN_PRIVSYN 8
#define ADEDLEN_PRIVID 4
-#define ADEID_NUM_V1 5
#define ADEID_NUM_V2 13
+#define ADEID_NUM_EA 5
-// #define ADEID_NUM_SFM 5
-/* sizeof SFM meta data */
-#define AD_SFM_LEN 60
-
-/* 589 */
-#define AD_DATASZ1 (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT + ADEDLEN_FILEI + ADEDLEN_FINDERI + \
- (ADEID_NUM_V1 * AD_ENTRY_LEN))
-
-#if AD_DATASZ1 != 589
-#error bad size for AD_DATASZ1
+#define AD_DATASZ2 (AD_HEADER_LEN + ADEDLEN_NAME + ADEDLEN_COMMENT + ADEDLEN_FILEI + \
+ ADEDLEN_FINDERI + ADEDLEN_DID + ADEDLEN_AFPFILEI + ADEDLEN_SHORTNAME + \
+ ADEDLEN_PRODOSFILEI + ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \
+ ADEDLEN_PRIVSYN + ADEDLEN_PRIVID + (ADEID_NUM_V2 * AD_ENTRY_LEN))
+#if AD_DATASZ2 != 741
+#error bad size for AD_DATASZ2
#endif
-#define AD_NEWSZ2 (ADEDLEN_DID + ADEDLEN_AFPFILEI + ADEDLEN_SHORTNAME + ADEDLEN_PRODOSFILEI \
- + ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
+#define AD_DATASZ_EA (AD_HEADER_LEN + (ADEID_NUM_EA * AD_ENTRY_LEN) + ADEDLEN_FINDERI + \
+ ADEDLEN_COMMENT + ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + ADEDLEN_PRIVID)
-/* 725 */
-#define AD_DATASZ2 (AD_DATASZ1 + AD_NEWSZ2 + ((ADEID_NUM_V2 - ADEID_NUM_V1) * AD_ENTRY_LEN))
-
-#if AD_DATASZ2 != 741
-#error bad size for AD_DATASZ2
+#if AD_DATASZ_EA != 342
+#error bad size for AD_DATASZ_EA
#endif
#define AD_DATASZ_MAX 1024
-#if AD_VERSION == AD_VERSION1
-#define AD_DATASZ AD_DATASZ1 /* hold enough for the entries */
-#elif AD_VERSION == AD_VERSION2
+
+#if AD_VERSION == AD_VERSION2
#define AD_DATASZ AD_DATASZ2
+#elif AD_VERSION == AD_VERSION_EA
+#define AD_DATASZ AD_DATASZ_EA
#endif
-/*
- * some legacy defines from netatalk-990130
- * (to keep from breaking certain packages)
- *
- */
-
-#define ADEDOFF_RFORK 589
-#define ADEDOFF_NAME 86
-#define ADEDOFF_COMMENT 341
-#define ADEDOFF_FINDERI 557
-#ifndef ADEDOFF_FILEI
-#define ADEDOFF_FILEI 541
-#endif
+#define RFORK_EA_ALLOCSIZE (128*1024) /* 128k */
typedef u_int32_t cnid_t;
-/*
- * The header of the AppleDouble Header File looks like this:
- *
- * NAME SIZE
- * ==== ====
- * Magic 4
- * Version 4
- * Home File System 16 (this becomes filler in ad v2)
- * Number of Entries 2
- * Entry Descriptors for each entry:
- * Entry ID 4
- * Offset 4
- * Length 4
- */
-
struct ad_entry {
- u_int32_t ade_off;
- u_int32_t ade_len;
+ uint32_t ade_off;
+ uint32_t ade_len;
};
typedef struct adf_lock_t {
struct ad_fd {
int adf_fd; /* -1: invalid, -2: symlink */
-
#ifndef HAVE_PREAD
off_t adf_off;
#endif
-
char *adf_syml;
int adf_flags;
int adf_excl;
+#if 0
adf_lock_t *adf_lock;
int adf_refcount, adf_lockcount, adf_lockmax;
+#endif
};
/* some header protection */
#define AD_INITED 0xad494e54 /* ad"INT" */
-struct adouble_fops;
+
+struct adouble;
+
+struct adouble_fops {
+ const char *(*ad_path)(const char *, int);
+ int (*ad_mkrf)(const char *);
+ int (*ad_rebuild_header)(struct adouble *);
+ int (*ad_header_read)(struct adouble *, struct stat *);
+ int (*ad_header_upgrade)(struct adouble *, const char *);
+};
struct adouble {
u_int32_t ad_magic;
struct ad_entry ad_eid[ ADEID_MAX ];
struct ad_fd ad_data_fork, ad_resource_fork, ad_metadata_fork;
struct ad_fd *ad_md; /* either ad_resource or ad_metadata */
-
int ad_flags; /* This really stores version info too (AD_VERSION*) */
int ad_adflags; /* ad_open flags adflags like ADFLAGS_DIR */
unsigned int ad_inited;
int ad_options;
- int ad_fileordir;
- int ad_refcount; /* used in afpd/ofork.c */
+ void *ad_resforkbuf; /* buffer for AD_VERSION_EA ressource fork */
+ size_t ad_resforkbufsize; /* size of ad_resforkbuf */
off_t ad_rlen; /* ressource fork len with AFP 3.0
- the header parameter size is too small.
- */
+ the header parameter size is too small. */
char *ad_m_name; /* mac name for open fork */
int ad_m_namelen;
+ bstring ad_fullpath; /* adouble EA need this */
struct adouble_fops *ad_ops;
- u_int16_t ad_open_forks; /* open forks (by others) */
-
-#ifdef USE_MMAPPED_HEADERS
- char *ad_data;
-#else
- char ad_data[AD_DATASZ_MAX];
-#endif
-};
-
-struct adouble_fops {
- char *(*ad_path)(const char *, int);
- int (*ad_mkrf)(char *);
- int (*ad_rebuild_header)(struct adouble *);
- int (*ad_check_header)(struct adouble *, struct stat *);
- int (*ad_header_read)(struct adouble *, struct stat *);
- int (*ad_header_upgrade)(struct adouble *, char *);
+ uint16_t ad_open_forks; /* open forks (by others) */
+ char ad_data[AD_DATASZ_MAX];
};
#define ADFLAGS_DF (1<<0)
-#define ADFLAGS_HF (1<<1)
-#define ADFLAGS_DIR (1<<2)
-/*
-#define ADFLAGS_NOADOUBLE (1<<3)
-*/
-#define ADFLAGS_V1COMPAT (1<<4)
-#define ADFLAGS_NOHF (1<<5) /* not an error if no ressource fork */
-#define ADFLAGS_RDONLY (1<<6) /* don't try readwrite */
-#define ADFLAGS_OPENFORKS (1<<7) /* check for open fork in ad_metadata function */
-#define ADFLAGS_RF (1<<8)
-#define ADFLAGS_MD ADFLAGS_HF /* (1<<9) */
-#define ADFLAGS_CREATE (1<<9)
-
-/* adouble v2 cnid cache */
+#define ADFLAGS_RF (1<<1)
+#define ADFLAGS_HF (1<<2)
+#define ADFLAGS_DIR (1<<3)
+#define ADFLAGS_NOHF (1<<4) /* not an error if no ressource fork */
+#define ADFLAGS_OPENFORKS (1<<5) /* check for open fork in ad_metadata function */
+
#define ADVOL_NODEV (1 << 0)
#define ADVOL_CACHE (1 << 1)
#define ADVOL_UNIXPRIV (1 << 2) /* adouble unix priv */
#define ad_unlock ad_fcntl_unlock
/* ad_open.c */
+extern const char *oflags2logstr(int oflags);
+extern const char *adflags2logstr(int adflags);
extern int ad_setfuid (const uid_t );
extern uid_t ad_getfuid (void );
extern char *ad_dir (const char *);
-extern char *ad_path (const char *, int);
-extern char *ad_path_osx (const char *, int);
-extern char *ad_path_ads (const char *, int);
-extern char *ad_path_sfm (const char *, int);
+extern const char *ad_path (const char *, int);
+extern const char *ad_path_ea (const char *, int);
extern int ad_mode (const char *, int);
extern int ad_mkdir (const char *, int);
extern void ad_init (struct adouble *, int, int );
-extern int ad_open (const char *, int, int, int, struct adouble *);
-extern int ad_openat (int dirfd, const char *, int, int, int, struct adouble *);
+extern int ad_open (struct adouble *ad, const char *path, int adflags, ...);
+extern int ad_openat (struct adouble *, int dirfd, const char *path, int adflags, ...);
extern int ad_refresh (struct adouble *);
extern int ad_stat (const char *, struct stat *);
extern int ad_metadata (const char *, int, struct adouble *);
extern int ad_metadataat (int, const char *, int, struct adouble *);
+#if 0
#define ad_open_metadata(name, flags, mode, adp)\
- ad_open(name, ADFLAGS_MD|(flags), O_RDWR |(mode), 0666, (adp))
+ ad_open(name, ADFLAGS_HF | (flags), O_RDWR |(mode), 0666, (adp))
+#endif
-#define ad_close_metadata(adp) ad_close( (adp), ADFLAGS_MD)
+#define ad_close_metadata(adp) ad_close( (adp), ADFLAGS_HF)
/* build a resource fork mode from the data fork mode:
* remove X mode and extend header to RW if R or W (W if R for locking),
return mode;
}
-/* ad_ea.c */
-ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size);
-ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size);
-ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size);
-ssize_t sys_listxattr (const char *path, char *list, size_t size);
-ssize_t sys_llistxattr (const char *path, char *list, size_t size);
-ssize_t sys_flistxattr (int filedes, char *list, size_t size);
-int sys_removexattr (const char *path, const char *name);
-int sys_lremovexattr (const char *path, const char *name);
-int sys_fremovexattr (int filedes, const char *name);
-int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags);
-int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags);
-int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags);
-int sys_copyxattr (const char *src, const char *dst);
-
/* ad_read.c/ad_write.c */
extern int sys_ftruncate(int fd, off_t length);
-
-extern ssize_t ad_read (struct adouble *, const u_int32_t,
- const off_t, char *, const size_t);
-extern ssize_t ad_pread (struct ad_fd *, void *, size_t, off_t);
-extern ssize_t ad_write (struct adouble *, const u_int32_t, off_t,
- const int, const char *, const size_t);
-extern ssize_t adf_pread (struct ad_fd *, void *, size_t, off_t);
-extern ssize_t adf_pwrite (struct ad_fd *, const void *, size_t, off_t);
-extern int ad_dtruncate (struct adouble *, const off_t);
-extern int ad_rtruncate (struct adouble *, const off_t);
+extern ssize_t ad_read(struct adouble *, uint32_t, off_t, char *, size_t);
+extern ssize_t ad_pread(struct ad_fd *, void *, size_t, off_t);
+extern ssize_t ad_write(struct adouble *, uint32_t, off_t, int, const char *, size_t);
+extern ssize_t adf_pread(struct ad_fd *, void *, size_t, off_t);
+extern ssize_t adf_pwrite(struct ad_fd *, const void *, size_t, off_t);
+extern int ad_dtruncate(struct adouble *, off_t);
+extern int ad_rtruncate(struct adouble *, off_t);
/* ad_size.c */
-extern off_t ad_size (const struct adouble *, const u_int32_t );
+extern off_t ad_size (const struct adouble *, uint32_t );
/* ad_mmap.c */
-extern void *ad_mmapread (struct adouble *, const u_int32_t,
- const off_t, const size_t);
-extern void *ad_mmapwrite (struct adouble *, const u_int32_t,
- const off_t, const int, const size_t);
+extern void *ad_mmapread(struct adouble *, uint32_t, off_t, size_t);
+extern void *ad_mmapwrite(struct adouble *, uint32_t, off_t, int, size_t);
#define ad_munmap(buf, len) (munmap((buf), (len)))
/* ad_date.c */
-extern int ad_setdate (struct adouble *, unsigned int, u_int32_t);
-extern int ad_getdate (const struct adouble *, unsigned int, u_int32_t *);
+extern int ad_setdate(struct adouble *, unsigned int, uint32_t);
+extern int ad_getdate(const struct adouble *, unsigned int, uint32_t *);
/* ad_attr.c */
-extern int ad_setattr (const struct adouble *, const u_int16_t);
-extern int ad_getattr (const struct adouble *, u_int16_t *);
-
-/* Note: starting with Netatalk 2.1 we do NOT alway set the name */
-extern int ad_setname (struct adouble *, const char *);
-
-#if AD_VERSION == AD_VERSION2
-extern int ad_setid (struct adouble *, const dev_t dev,const ino_t ino, const u_int32_t, const u_int32_t, const void *);
-extern u_int32_t ad_getid (struct adouble *, const dev_t, const ino_t, const cnid_t, const void *);
-extern u_int32_t ad_forcegetid (struct adouble *adp);
-#else
-#define ad_setid(a, b, c)
-#endif
+extern int ad_setattr(const struct adouble *, uint16_t);
+extern int ad_getattr(const struct adouble *, uint16_t *);
+extern int ad_setname(struct adouble *, const char *);
+extern int ad_setid(struct adouble *, dev_t dev, ino_t ino, uint32_t, uint32_t, const void *);
+extern u_int32_t ad_getid(struct adouble *, dev_t, ino_t, cnid_t, const void *);
+extern u_int32_t ad_forcegetid(struct adouble *adp);
#ifdef WITH_SENDFILE
-extern int ad_readfile_init(const struct adouble *ad,
- const int eid, off_t *off,
- const int end);
+extern int ad_readfile_init(const struct adouble *ad, int eid, off_t *off, int end);
#endif
#if 0
#ifdef HAVE_SENDFILE_WRITE
-extern ssize_t ad_writefile (struct adouble *, const int,
- const int, off_t, const int, const size_t);
+extern ssize_t ad_writefile(struct adouble *, int, int, off_t, int, size_t);
#endif /* HAVE_SENDFILE_WRITE */
#endif /* 0 */
char *volpath; /* Volume path this particular CNID db refers to. */
void *_private; /* back-end speficic data */
- cnid_t (*cnid_add) (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
- char *name, const size_t, cnid_t hint);
+ cnid_t (*cnid_add) (struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+ const char *name, size_t, cnid_t hint);
int (*cnid_delete) (struct _cnid_db *cdb, cnid_t id);
- cnid_t (*cnid_get) (struct _cnid_db *cdb, const cnid_t did, char *name, const size_t);
- cnid_t (*cnid_lookup) (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
- char *name, const size_t);
+ cnid_t (*cnid_get) (struct _cnid_db *cdb, cnid_t did, const char *name, size_t);
+ cnid_t (*cnid_lookup) (struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+ const char *name, size_t);
cnid_t (*cnid_nextid) (struct _cnid_db *cdb);
char * (*cnid_resolve) (struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len);
- int (*cnid_update) (struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
- const cnid_t did, char *name, const size_t len);
+ int (*cnid_update) (struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+ cnid_t did, const char *name, size_t len);
void (*cnid_close) (struct _cnid_db *cdb);
int (*cnid_getstamp) (struct _cnid_db *cdb, void *buffer, const size_t len);
- cnid_t (*cnid_rebuild_add) (struct _cnid_db *, const struct stat *, const cnid_t,
- char *, const size_t, cnid_t);
- int (*cnid_find) (struct _cnid_db *cdb, char *name, size_t namelen,
+ cnid_t (*cnid_rebuild_add) (struct _cnid_db *, const struct stat *, cnid_t,
+ const char *, size_t, cnid_t);
+ int (*cnid_find) (struct _cnid_db *cdb, const char *name, size_t namelen,
void *buffer, size_t buflen);
};
typedef struct _cnid_db cnid_db;
ino_t ino;
uint32_t type;
cnid_t did;
- char *name;
+ const char *name;
size_t namelen;
};
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/time.h>
+#include <sys/socket.h>
#include <signal.h>
#include <netinet/in.h>
#include <atalk/server_child.h>
#include <netatalk/endian.h>
-#ifdef __OpenBSD__
-#include <sys/socket.h>
-#endif
-
/* What a DSI packet looks like:
0 32
|-------------------------------|
/*
- $Id: ea.h,v 1.11 2010-03-12 15:16:49 franklahm Exp $
Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
This program is free software; you can redistribute it and/or modify
#include <config.h>
#endif
+#if HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#elif HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
+#ifdef HAVE_SYS_EA_H
+#include <sys/ea.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
+
#ifdef HAVE_SOLARIS_ACLS
#include <sys/acl.h>
#endif
+#ifndef ENOATTR
+#define ENOATTR ENODATA
+#endif
+
#include <atalk/vfs.h>
/*
#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
#endif
+/* Names for our Extended Attributes adouble data */
+#define AD_EA_META "org.netatalk.Metadata"
+#define AD_EA_RESO "org.netatalk.ResourceFork"
+#define NOT_NETATALK_EA(a) (strcmp((a), AD_EA_META) != 0) && (strcmp((a), AD_EA_RESO) != 0)
+
+/****************************************************************************************
+ * Wrappers for native EA functions taken from Samba
+ ****************************************************************************************/
+ssize_t sys_getxattr (const char *path, const char *name, void *value, size_t size);
+ssize_t sys_lgetxattr (const char *path, const char *name, void *value, size_t size);
+ssize_t sys_fgetxattr (int filedes, const char *name, void *value, size_t size);
+ssize_t sys_listxattr (const char *path, char *list, size_t size);
+ssize_t sys_llistxattr (const char *path, char *list, size_t size);
+ssize_t sys_flistxattr (int filedes, char *list, size_t size);
+int sys_removexattr (const char *path, const char *name);
+int sys_lremovexattr (const char *path, const char *name);
+int sys_fremovexattr (int filedes, const char *name);
+int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags);
+int sys_lsetxattr (const char *path, const char *name, const void *value, size_t size, int flags);
+int sys_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags);
+int sys_copyxattr (const char *src, const char *dst);
/****************************************************************************************
* Stuff for our implementation of storing EAs in files in .AppleDouble dirs
/* lock file path. this should be re-organized a bit. */
#if ! defined (_PATH_LOCKDIR)
# if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-# define _PATH_LOCKDIR "/var/run/"
+# define _PATH_LOCKDIR /var/run/
# elif defined (BSD4_4)
# ifdef MACOSX_SERVER
-# define _PATH_LOCKDIR "/var/run/"
+# define _PATH_LOCKDIR /var/run/
# else
-# define _PATH_LOCKDIR "/var/spool/lock/"
+# define _PATH_LOCKDIR /var/spool/lock/
# endif
# elif defined (linux)
-# define _PATH_LOCKDIR "/var/lock/"
+# define _PATH_LOCKDIR /var/lock/
# else
-# define _PATH_LOCKDIR "/var/spool/locks/"
+# define _PATH_LOCKDIR /var/spool/locks/
# endif
#endif
#define _PATH_ATALKDEBUG "/tmp/atalkd.debug"
#define _PATH_ATALKDTMP "atalkd.tmp"
#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-# define _PATH_ATALKDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"atalkd.pid")
+# define _PATH_ATALKDLOCK ATALKPATHCAT("_PATH_LOCKDIR","atalkd.pid")
#else
-# define _PATH_ATALKDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"atalkd")
+# define _PATH_ATALKDLOCK ATALKPATHCAT("_PATH_LOCKDIR","atalkd")
#endif
/*
*/
#define _PATH_TMPPAGEORDER "/tmp/psorderXXXXXX"
#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-# define _PATH_PAPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"papd.pid")
+# define _PATH_PAPDLOCK ATALKPATHCAT("_PATH_LOCKDIR","papd.pid")
#else
-# define _PATH_PAPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"papd")
+# define _PATH_PAPDLOCK ATALKPATHCAT("_PATH_LOCKDIR","papd")
#endif
/*
*/
#define _PATH_AFPTKT "/tmp/AFPtktXXXXXX"
#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-# define _PATH_AFPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"afpd.pid")
+# define _PATH_AFPDLOCK ATALKPATHCAT("_PATH_LOCKDIR","afpd.pid")
#else
-# define _PATH_AFPDLOCK ATALKPATHCAT(_PATH_LOCKDIR,"afpd")
+# define _PATH_AFPDLOCK ATALKPATHCAT("_PATH_LOCKDIR","afpd")
#endif
/*
* cnid_metad paths
*/
#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__)
-# define _PATH_CNID_METAD_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"cnid_metad.pid")
+# define _PATH_CNID_METAD_LOCK ATALKPATHCAT("_PATH_LOCKDIR","cnid_metad.pid")
#else
-# define _PATH_CNID_METAD_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"cnid_metad")
+# define _PATH_CNID_METAD_LOCK ATALKPATHCAT("_PATH_LOCKDIR","cnid_metad")
#endif
#endif /* atalk/paths.h */
#include <sys/cdefs.h>
#include <sys/types.h>
-#ifdef HAVE_UNISTD_H
+#include <sys/socket.h>
#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+
+#ifndef NO_DDP
#include <netatalk/at.h>
+#endif
#include <atalk/unicode.h>
/* exit error codes */
#define diatolower(x) _dialowermap[(unsigned char) (x)]
#define diatoupper(x) _diacasemap[(unsigned char) (x)]
+#ifndef NO_DDP
extern int atalk_aton (char *, struct at_addr *);
+#endif
extern void bprint (char *, int);
extern int strdiacasecmp (const char *, const char *);
extern int strndiacasecmp (const char *, const char *, size_t);
* unix.c
*****************************************************************/
+extern const char *abspath(const char *name);
extern const char *getcwdpath(void);
extern char *stripped_slashes_basename(char *p);
extern int lchdir(const char *dir);
#define UUID_BINSIZE 16
#define UUID_STRINGSIZE 36
-typedef unsigned char *uuidp_t;
+typedef const unsigned char *uuidp_t;
typedef unsigned char atalk_uuid_t[UUID_BINSIZE];
typedef enum {UUID_USER = 1, UUID_GROUP, UUID_LOCAL} uuidtype_t;
* Interface
********************************************************/
-extern int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid);
-extern int getnamefromuuid( const uuidp_t uuidp, char **name, uuidtype_t *type);
-extern const char *uuid_bin2string(unsigned char *uuid);
-extern void uuid_string2bin( const char *uuidstring, uuidp_t uuid);
+extern int getuuidfromname( const char *name, uuidtype_t type, unsigned char *uuid);
+extern int getnamefromuuid( uuidp_t uuidp, char **name, uuidtype_t *type);
+extern const char *uuid_bin2string(const unsigned char *uuid);
+extern void uuid_string2bin( const char *uuidstring, unsigned char *uuid);
#endif /* AFP_UUID_H */
int v_adouble; /* default adouble format */
int v_ad_options;
int v_vfs_ea;
- char *(*ad_path)(const char *, int);
+ const char *(*ad_path)(const char *, int);
char *v_dbd_host;
char *v_dbd_port;
};
char *v_veto;
int v_adouble; /* adouble format: v1, v2, sfm ... */
int v_ad_options; /* adouble option NODEV, NOCACHE, etc.. */
- char *(*ad_path)(const char *, int);
+ const char *(*ad_path)(const char *, int);
struct _cnid_db *v_cdb;
char v_stamp[ADEDLEN_PRIVSYN];
VolSpace v_limitsize; /* Size limit, if any, in MiB */
# Makefile.am for libatalk/
-SUBDIRS = acl adouble asp atp bstring compat cnid dsi nbp netddp tdb util unicode vfs
+SUBDIRS = acl adouble bstring compat cnid dsi tdb util unicode vfs
lib_LTLIBRARIES = libatalk.la
libatalk_la_LIBADD = \
acl/libacl.la \
adouble/libadouble.la \
- asp/libasp.la \
- atp/libatp.la \
bstring/libbstring.la \
compat/libcompat.la \
dsi/libdsi.la \
- nbp/libnbp.la \
- netddp/libnetddp.la \
util/libutil.la \
tdb/libtdb.la \
unicode/libunicode.la \
libatalk_la_DEPENDENCIES = \
acl/libacl.la \
adouble/libadouble.la \
- asp/libasp.la \
- atp/libatp.la \
bstring/libbstring.la \
compat/libcompat.la \
dsi/libdsi.la \
- nbp/libnbp.la \
- netddp/libnetddp.la \
util/libutil.la \
tdb/libtdb.la \
unicode/libunicode.la \
libatalk_la_LDFLAGS = -static
+if USE_APPLETALK
+SUBDIRS += asp atp nbp netddp
+libatalk_la_LIBADD += \
+ asp/libasp.la \
+ atp/libatp.la \
+ nbp/libnbp.la \
+ netddp/libnetddp.la
+libatalk_la_DEPENDENCIES += \
+ asp/libasp.la \
+ atp/libatp.la \
+ nbp/libnbp.la \
+ netddp/libnetddp.la
+endif
typedef struct cacheduser {
unsigned long uid; /* for future use */
uuidtype_t type;
- uuidp_t uuid;
+ unsigned char *uuid;
char *name;
time_t creationtime;
struct cacheduser *prev;
int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid _U_) {
int ret = 0;
char *name = NULL;
- uuidp_t uuid;
+ unsigned char *uuid;
cacheduser_t *cacheduser = NULL;
cacheduser_t *entry;
unsigned char hash;
/*
* Caller provides buffer uuid for result
*/
-int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
+int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid) {
int ret;
unsigned char hash;
cacheduser_t *entry;
int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid _U_) {
int ret = 0;
char *name = NULL;
- uuidp_t uuid;
+ unsigned char *uuid;
cacheduser_t *cacheduser = NULL;
cacheduser_t *entry;
unsigned char hash;
* uuid: if found copies uuid into this buffer
* returns 0 on success, !=0 if not found or on errors
*/
-extern int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid);
+extern int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid);
/*
* inname: name
/* sorry, no ACLs for symlinks */
return 0;
- if ( ! (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))) {
+ if ( ! ((S_ISREG(st.st_mode)) || (S_ISDIR(st.st_mode)))) {
LOG(log_warning, logtype_afpd, "get_nfsv4_acl(\"%s/%s\"): special", getcwdpath(), name);
return 0;
}
* convert ascii string that can include dashes to binary uuid.
* caller must provide a buffer.
*/
-void uuid_string2bin( const char *uuidstring, uuidp_t uuid) {
+void uuid_string2bin( const char *uuidstring, unsigned char *uuid) {
int nibble = 1;
int i = 0;
unsigned char c, val = 0;
*
* Returns pointer to static buffer.
*/
-const char *uuid_bin2string(unsigned char *uuid) {
+const char *uuid_bin2string(const unsigned char *uuid) {
static char uuidstring[UUID_STRINGSIZE + 1];
int i = 0;
* uuid: pointer to uuid_t storage that the caller must provide
* returns 0 on success !=0 on errror
*/
-int getuuidfromname( const char *name, uuidtype_t type, uuidp_t uuid) {
+int getuuidfromname( const char *name, uuidtype_t type, unsigned char *uuid) {
int ret = 0;
#ifdef HAVE_LDAP
char *uuid_string = NULL;
*
* Caller must free name appropiately.
*/
-int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) {
+int getnamefromuuid(uuidp_t uuidp, char **name, uuidtype_t *type) {
int ret;
ret = search_cachebyuuid( uuidp, name, type);
libadouble_la_SOURCES = ad_open.c ad_flush.c ad_read.c ad_write.c ad_size.c \
ad_mmap.c ad_lock.c ad_date.c ad_attr.c ad_sendfile.c
-noinst_HEADERS = ad_private.h
+noinst_HEADERS = ad_lock.h
u_int16_t fflags;
*attr = 0;
- if (ad->ad_version == AD_VERSION1) {
- if (ad_getentryoff(ad, ADEID_FILEI)) {
- memcpy(attr, ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR,
- sizeof(u_int16_t));
- }
- }
-#if AD_VERSION == AD_VERSION2
- else if (ad->ad_version == AD_VERSION2) {
+ if (ad->ad_version == AD_VERSION2) {
if (ad_getentryoff(ad, ADEID_AFPFILEI)) {
memcpy(attr, ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR, 2);
}
}
}
-#endif
- else
- return -1;
*attr |= htons(ad->ad_open_forks);
if (ad->ad_adflags & ADFLAGS_DIR)
attr &= ~(ATTRBIT_MULTIUSER | ATTRBIT_NOWRITE | ATTRBIT_NOCOPY);
- if (ad->ad_version == AD_VERSION1) {
- if (ad_getentryoff(ad, ADEID_FILEI)) {
- memcpy(ad_entry(ad, ADEID_FILEI) + FILEIOFF_ATTR, &attr,
- sizeof(attr));
- }
- }
-#if AD_VERSION == AD_VERSION2
- else if (ad->ad_version == AD_VERSION2) {
+ if (ad->ad_version == AD_VERSION2) {
if (ad_getentryoff(ad, ADEID_AFPFILEI) && ad_getentryoff(ad, ADEID_FINDERI)) {
memcpy(ad_entry(ad, ADEID_AFPFILEI) + AFPFILEIOFF_ATTR, &attr, sizeof(attr));
memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &fflags, 2);
}
}
-#endif
- else
- return -1;
return 0;
}
* save file/folder ID in AppleDoubleV2 netatalk private parameters
* return 1 if resource fork has been modified
*/
-#if AD_VERSION == AD_VERSION2
int ad_setid (struct adouble *adp, const dev_t dev, const ino_t ino , const u_int32_t id, const cnid_t did, const void *stamp)
{
if ((adp->ad_flags == AD_VERSION2) && (adp->ad_options & ADVOL_CACHE)) {
}
return 0;
}
-#endif
/* -----------------
* set resource fork filename attribute.
#include <string.h>
#include <atalk/adouble.h>
-int ad_setdate(struct adouble *ad,
- unsigned int dateoff, u_int32_t date)
+int ad_setdate(struct adouble *ad,
+ unsigned int dateoff, u_int32_t date)
{
- int xlate = (dateoff & AD_DATE_UNIX);
+ int xlate = (dateoff & AD_DATE_UNIX);
- dateoff &= AD_DATE_MASK;
- if (xlate)
- date = AD_DATE_FROM_UNIX(date);
+ dateoff &= AD_DATE_MASK;
+ if (xlate)
+ date = AD_DATE_FROM_UNIX(date);
- if (ad->ad_version == AD_VERSION1) {
-
- if (!ad_getentryoff(ad, ADEID_FILEI))
- return -1;
-
- if (dateoff > AD_DATE_BACKUP)
- return -1;
- memcpy(ad_entry(ad, ADEID_FILEI) + dateoff, &date, sizeof(date));
-
- } else if (ad->ad_version == AD_VERSION2) {
if (!ad_getentryoff(ad, ADEID_FILEDATESI))
return -1;
-
+
if (dateoff > AD_DATE_ACCESS)
return -1;
memcpy(ad_entry(ad, ADEID_FILEDATESI) + dateoff, &date, sizeof(date));
- } else
- return -1;
-
- return 0;
+ return 0;
}
int ad_getdate(const struct adouble *ad,
- unsigned int dateoff, u_int32_t *date)
+ unsigned int dateoff, u_int32_t *date)
{
- int xlate = (dateoff & AD_DATE_UNIX);
-
- dateoff &= AD_DATE_MASK;
- if (ad->ad_version == AD_VERSION1) {
- if (dateoff > AD_DATE_BACKUP)
- return -1;
- if (!ad_getentryoff(ad, ADEID_FILEI))
- return -1;
- memcpy(date, ad_entry(ad, ADEID_FILEI) + dateoff, sizeof(u_int32_t));
+ int xlate = (dateoff & AD_DATE_UNIX);
- } else if (ad->ad_version == AD_VERSION2) {
+ dateoff &= AD_DATE_MASK;
if (!ad_getentryoff(ad, ADEID_FILEDATESI))
return -1;
if (dateoff > AD_DATE_ACCESS)
- return -1;
+ return -1;
memcpy(date, ad_entry(ad, ADEID_FILEDATESI) + dateoff, sizeof(u_int32_t));
- } else
- return -1;
-
- if (xlate)
- *date = AD_DATE_TO_UNIX(*date);
- return 0;
+ if (xlate)
+ *date = AD_DATE_TO_UNIX(*date);
+ return 0;
}
/*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
+ * Copyright (c) 2010 Frank Lahm
* All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
#endif /* HAVE_CONFIG_H */
#include <string.h>
-#include <atalk/adouble.h>
-
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
-#include "ad_private.h"
-#if AD_VERSION == AD_VERSION1
-
-#define EID_DISK(a) (a)
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
+#include <atalk/logger.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
-#else
+#include "ad_lock.h"
static const u_int32_t set_eid[] = {
0,1,2,3,4,5,6,7,8,
};
#define EID_DISK(a) (set_eid[a])
-#endif
-/* rebuild the adouble header
- * XXX should be in a separate file ?
+/*
+ * Rebuild any header information that might have changed.
*/
int ad_rebuild_adouble_header(struct adouble *ad)
{
u_int32_t eid;
u_int32_t temp;
-
u_int16_t nent;
char *buf, *nentp;
+ int len;
- /*
- * Rebuild any header information that might have changed.
- */
buf = ad->ad_data;
temp = htonl( ad->ad_magic );
memcpy(buf, &temp, sizeof( temp ));
buf += sizeof( temp );
- memcpy(buf, ad->ad_filler, sizeof( ad->ad_filler ));
buf += sizeof( ad->ad_filler );
nentp = buf;
}
nent = htons( nent );
memcpy(nentp, &nent, sizeof( nent ));
- return ad_getentryoff(ad, ADEID_RFORK);
+
+ switch (ad->ad_flags) {
+ case AD_VERSION2:
+ len = ad_getentryoff(ad, ADEID_RFORK);
+ break;
+ case AD_VERSION_EA:
+ len = AD_DATASZ_EA;
+ break;
+ default:
+ LOG(log_error, logtype_afpd, "Unexpected adouble version");
+ len = 0;
+ break;
+ }
+
+ return len;
}
/* -------------------
return 0;
}
-/* ------------------- */
-int ad_rebuild_sfm_header(struct adouble *ad)
-{
- u_int32_t temp;
-
- u_int16_t attr;
- char *buf;
-
- /*
- * Rebuild any header information that might have changed.
- */
- buf = ad->ad_data;
- /* FIXME */
-/* temp = htonl( ad->ad_magic ); */
- temp = ad->ad_magic;
- memcpy(buf, &temp, sizeof( temp ));
-
-/* temp = htonl( ad->ad_version ); */
- temp = ad->ad_version;
- memcpy(buf +4, &temp, sizeof( temp ));
-
- /* need to save attrib */
- if (!ad_getattr(ad, &attr)) {
- attr &= ~htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN);
-
- memcpy(buf +48 +4, &attr, sizeof(attr));
-
- }
- return AD_SFM_LEN;
-}
-
-
-int ad_flush( struct adouble *ad)
+int ad_flush(struct adouble *ad)
{
int len;
if (( ad->ad_md->adf_flags & O_RDWR )) {
- /* sync our header */
- if (ad->ad_rlen > 0xffffffff) {
- ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
- }
- else {
- ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
+ if (ad_getentryoff(ad, ADEID_RFORK)) {
+ if (ad->ad_rlen > 0xffffffff)
+ ad_setentrylen(ad, ADEID_RFORK, 0xffffffff);
+ else
+ ad_setentrylen(ad, ADEID_RFORK, ad->ad_rlen);
}
len = ad->ad_ops->ad_rebuild_header(ad);
- if (adf_pwrite(ad->ad_md, ad->ad_data, len, 0) != len) {
- if ( errno == 0 ) {
- errno = EIO;
+ switch (ad->ad_flags) {
+ case AD_VERSION2:
+ if (adf_pwrite(ad->ad_md, ad->ad_data, len, 0) != len) {
+ if (errno == 0)
+ errno = EIO;
+ return( -1 );
+ }
+ break;
+ case AD_VERSION_EA:
+ if (sys_lsetxattr(cfrombstr(ad->ad_fullpath), AD_EA_META, ad->ad_data, AD_DATASZ_EA, 0) != 0) {
+ LOG(log_error, logtype_afpd, "ad_flush: sys_fsetxattr error: %s",
+ strerror(errno));
+ return -1;
}
- return( -1 );
+ break;
+ default:
+ LOG(log_error, logtype_afpd, "ad_flush: unexpected adouble version");
+ return -1;
}
}
return( 0 );
}
-/* use refcounts so that we don't have to re-establish fcntl locks. */
+/*!
+ * Close a struct adouble freeing all resources
+ *
+ * This close the whole thing, regardless of what you pass in adflags!
+ */
int ad_close( struct adouble *ad, int adflags)
{
- int err = 0;
+ int err = 0;
- if ((adflags & ADFLAGS_DF)
- && (ad_data_fileno(ad) >= 0 || ad_data_fileno(ad) == -2) /* -2 means symlink */
- && --ad->ad_data_fork.adf_refcount == 0) {
- if (ad->ad_data_fork.adf_syml != NULL) {
+ LOG(log_debug, logtype_default, "ad_close(\"%s\", %s)",
+ cfrombstr(ad->ad_fullpath),
+ adflags2logstr(adflags));
+
+ if (ad_data_fileno(ad) != -1) {
+ if ((ad_data_fileno(ad) == -2) && (ad->ad_data_fork.adf_syml != NULL)) {
free(ad->ad_data_fork.adf_syml);
- ad->ad_data_fork.adf_syml = 0;
+ ad->ad_data_fork.adf_syml = NULL;
} else {
if ( close( ad_data_fileno(ad) ) < 0 )
err = -1;
}
ad_data_fileno(ad) = -1;
adf_lock_free(&ad->ad_data_fork);
+ ad->ad_adflags &= ~ADFLAGS_DF;
}
- if (!( adflags & ADFLAGS_HF )) {
- return err;
- }
-
- /* meta /resource fork */
-
- if ( ad_meta_fileno(ad) != -1 && !(--ad->ad_md->adf_refcount)) {
- if ( close( ad_meta_fileno(ad) ) < 0 ) {
+ if (ad_meta_fileno(ad) != -1) {
+ if ( close( ad_meta_fileno(ad) ) < 0 )
err = -1;
- }
ad_meta_fileno(ad) = -1;
adf_lock_free(ad->ad_md);
+ ad->ad_adflags &= ~ADFLAGS_HF;
}
- if (ad->ad_flags != AD_VERSION1_SFM) {
- return err;
+ if (ad->ad_resforkbuf) {
+ free(ad->ad_resforkbuf);
+ ad->ad_resforkbuf = NULL;
+ ad->ad_adflags &= ~ADFLAGS_RF;
}
- if ((adflags & ADFLAGS_DIR)) {
- return err;
- }
-
- if ( ad_reso_fileno(ad) != -1 && !(--ad->ad_resource_fork.adf_refcount)) {
- if ( close( ad_reso_fileno(ad) ) < 0 ) {
- err = -1;
- }
- ad_reso_fileno(ad) = -1;
- adf_lock_free(&ad->ad_resource_fork);
+ if (ad->ad_fullpath) {
+ bdestroy(ad->ad_fullpath);
+ ad->ad_fullpath = NULL;
}
return err;
#include <string.h>
-#include "ad_private.h"
+#include "ad_lock.h"
/* translate between ADLOCK styles and specific locking mechanisms */
#define XLATE_FLOCK(type) ((type) == ADLOCK_RD ? LOCK_SH : \
/* ----------------------- */
static int OVERLAP(off_t a, off_t alen, off_t b, off_t blen)
{
- return (!alen && a <= b) ||
- (!blen && b <= a) ||
- ( (a + alen > b) && (b + blen > a) );
+ return (!alen && a <= b) ||
+ (!blen && b <= a) ||
+ ( (a + alen > b) && (b + blen > a) );
}
/* allocation for lock regions. we allocate aggressively and shrink
/* remove a lock and compact space if necessary */
static void adf_freelock(struct ad_fd *ad, const int i)
{
+#if 0
adf_lock_t *lock = ad->adf_lock + i;
if (--(*lock->refcount) < 1) {
ad->adf_lockmax = ad->adf_lockcount + ARRAY_FREE_DELTA;
}
}
+#endif
}
*/
static void adf_unlock(struct ad_fd *ad, const int fork)
{
+#if 0
adf_lock_t *lock = ad->adf_lock;
int i;
lock = ad->adf_lock;
}
}
+#endif
}
/* relock any byte lock that overlaps off/len. unlock everything
* else. */
-static void adf_relockrange(struct ad_fd *ad, int fd,
- const off_t off, const off_t len)
+static void adf_relockrange(struct ad_fd *ad, int fd, off_t off, off_t len)
{
+#if 0
adf_lock_t *lock = ad->adf_lock;
int i;
if (OVERLAP(off, len, lock[i].lock.l_start, lock[i].lock.l_len))
set_lock(fd, F_SETLK, &lock[i].lock);
}
+#endif
}
/* find a byte lock that overlaps off/len for a particular open fork */
static int adf_findlock(struct ad_fd *ad,
- const int fork, const int type,
- const off_t off,
- const off_t len)
+ const int fork, const int type,
+ const off_t off,
+ const off_t len)
{
+#if 0
adf_lock_t *lock = ad->adf_lock;
int i;
return i;
}
}
-
+#endif
return -1;
}
/* search other fork lock lists */
static int adf_findxlock(struct ad_fd *ad,
- const int fork, const int type,
- const off_t off,
- const off_t len)
+ const int fork, const int type,
+ const off_t off,
+ const off_t len)
{
+#if 0
adf_lock_t *lock = ad->adf_lock;
int i;
OVERLAP(off, len, lock[i].lock.l_start, lock[i].lock.l_len))
return i;
}
+#endif
return -1;
}
/* ------------------ */
int ad_fcntl_lock(struct adouble *ad, const u_int32_t eid, const int locktype,
- const off_t off, const off_t len, const int fork)
+ const off_t off, const off_t len, const int fork)
{
+#if 0
struct flock lock;
struct ad_fd *adf;
adf_lock_t *adflock;
lock.l_type = F_UNLCK;
if (!adf->adf_excl) set_lock(adf->adf_fd, F_SETLK, &lock);
return -1;
+#endif
+ return 0;
}
/* -------------------------
*/
static int testlock(struct ad_fd *adf, off_t off, off_t len)
{
+#if 0
struct flock lock;
adf_lock_t *plock;
int i;
return 0;
}
return 1;
+#endif
+ return 0;
}
/* --------------- */
int ad_testlock(struct adouble *ad, int eid, const off_t off)
{
+ return 0;
+#if 0
struct ad_fd *adf;
off_t lock_offset;
lock_offset = hf2off(off);
}
return testlock(adf, lock_offset, 1);
+#endif
}
/* -------------------------
*/
u_int16_t ad_openforks(struct adouble *ad, u_int16_t attrbits)
{
+ return 0;
+#if 0
u_int16_t ret = 0;
struct ad_fd *adf;
off_t off;
}
return ret;
+#endif
}
/* -------------------------
int ad_fcntl_tmplock(struct adouble *ad, const u_int32_t eid, const int locktype,
const off_t off, const off_t len, const int fork)
{
+ return 0;
+#if 0
struct flock lock;
struct ad_fd *adf;
int err;
adf_relockrange(adf, adf->adf_fd, lock.l_start, len);
return err;
+#endif
}
/* -------------------------
*/
int ad_excl_lock(struct adouble *ad, const u_int32_t eid)
{
+ return 0;
+#if 0
struct ad_fd *adf;
struct flock lock;
int err;
if (!err)
adf->adf_excl = 1;
return err;
+#endif
}
/* --------------------- */
void ad_fcntl_unlock(struct adouble *ad, const int fork)
{
+ return;
+#if 0
if (ad_data_fileno(ad) != -1) {
adf_unlock(&ad->ad_data_fork, fork);
}
adf_unlock(&ad->ad_resource_fork, fork);
}
- if (ad->ad_flags != AD_VERSION1_SFM) {
+ if (ad->ad_flags != AD_VERSION_EA) {
return;
}
if (ad_meta_fileno(ad) != -1) {
adf_unlock(&ad->ad_metadata_fork, fork);
}
-
+#endif
}
--- /dev/null
+#ifndef LIBATALK_ADOUBLE_AD_PRIVATE_H
+#define LIBATALK_ADOUBLE_AD_PRIVATE_H 1
+
+#include <atalk/adouble.h>
+
+/* this is so that we can keep lists of fds referencing the same file
+ * around. that way, we can honor locks created by the same process
+ * with the same file. */
+
+#define adf_lock_free(a) \
+ do { \
+ ; \
+ } while (0)
+
+#endif /* libatalk/adouble/ad_private.h */
/*
- * $Id: ad_mmap.c,v 1.6 2008-12-03 18:35:44 didg Exp $
- *
* ad_mmap provides interfaces to memory mapped files. as this is the
* case, we don't have to deal w/ temporary buffers such as
* ad_data. the ad_mmap routines are designed to not interact w/ the
#include <atalk/adouble.h>
#include <string.h>
-#include "ad_private.h"
+#include "ad_lock.h"
static void *ad_mmap(const size_t length, const int prot,
const int flags, const int fd,
/*
* Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
* Copyright (c) 1990,1991 Regents of The University of Michigan.
+ * Copyright (c) 2010 Frank Lahm
+ *
* All Rights Reserved.
*
* Permission to use, copy, modify, and distribute this software and
#endif /* HAVE_CONFIG_H */
#include <errno.h>
-
-#include <atalk/adouble.h>
#include <sys/param.h>
-#include <atalk/logger.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
#include <atalk/util.h>
-#include <string.h>
+#include <atalk/ea.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
-#include "ad_private.h"
-#include <stdlib.h>
+#include "ad_lock.h"
#ifndef MAX
#define MAX(a, b) ((a) < (b) ? (b) : (a))
#endif /* ! MAX */
-/*
- * AppleDouble entry default offsets.
- * The layout looks like this:
- *
- * this is the v1 layout:
- * 255 200 16 32 N
- * | NAME | COMMENT | FILEI | FINDERI | RFORK |
- *
- * we need to change it to look like this:
- *
- * v2 layout:
- * field length (in bytes)
- * NAME 255
- * COMMENT 200
- * FILEDATESI 16 replaces FILEI
- * FINDERI 32
- * DID 4 new
- * AFPFILEI 4 new
- * SHORTNAME 12 8.3 new
- * RFORK N
- *
- * so, all we need to do is replace FILEI with FILEDATESI, move RFORK,
- * and add in the new fields.
- *
- * NOTE: the HFS module will need similar modifications to interact with
- * afpd correctly.
- */
+#ifdef HAVE_PREAD
+# define AD_SET(a)
+#else
+# define AD_SET(a) a = 0
+#endif
#define ADEDOFF_MAGIC (0)
#define ADEDOFF_VERSION (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
/* initial lengths of some of the fields */
#define ADEDLEN_INIT 0
-/* make sure we don't redefine ADEDOFF_FILEI */
-#ifdef ADEDOFF_FILEI
-#undef ADEDOFF_FILEI
-#endif /* ADEDOFF_FILEI */
-
-#define ADEDOFF_NAME_V1 (AD_HEADER_LEN + ADEID_NUM_V1*AD_ENTRY_LEN)
-#define ADEDOFF_COMMENT_V1 (ADEDOFF_NAME_V1 + ADEDLEN_NAME)
-#define ADEDOFF_FILEI (ADEDOFF_COMMENT_V1 + ADEDLEN_COMMENT)
-#define ADEDOFF_FINDERI_V1 (ADEDOFF_FILEI + ADEDLEN_FILEI)
-#define ADEDOFF_RFORK_V1 (ADEDOFF_FINDERI_V1 + ADEDLEN_FINDERI)
-
/* i stick things in a slightly different order than their eid order in
* case i ever want to separate RootInfo behaviour from the rest of the
* stuff. */
+
+/* ad:v2 */
#define ADEDOFF_NAME_V2 (AD_HEADER_LEN + ADEID_NUM_V2*AD_ENTRY_LEN)
#define ADEDOFF_COMMENT_V2 (ADEDOFF_NAME_V2 + ADEDLEN_NAME)
#define ADEDOFF_FILEDATESI (ADEDOFF_COMMENT_V2 + ADEDLEN_COMMENT)
#define ADEDOFF_FINDERI_V2 (ADEDOFF_FILEDATESI + ADEDLEN_FILEDATESI)
-#define ADEDOFF_DID (ADEDOFF_FINDERI_V2 + ADEDLEN_FINDERI)
+#define ADEDOFF_DID (ADEDOFF_FINDERI_V2 + ADEDLEN_FINDERI)
#define ADEDOFF_AFPFILEI (ADEDOFF_DID + ADEDLEN_DID)
#define ADEDOFF_SHORTNAME (ADEDOFF_AFPFILEI + ADEDLEN_AFPFILEI)
#define ADEDOFF_PRODOSFILEI (ADEDOFF_SHORTNAME + ADEDLEN_SHORTNAME)
#define ADEDOFF_PRIVINO (ADEDOFF_PRIVDEV + ADEDLEN_PRIVDEV)
#define ADEDOFF_PRIVSYN (ADEDOFF_PRIVINO + ADEDLEN_PRIVINO)
#define ADEDOFF_PRIVID (ADEDOFF_PRIVSYN + ADEDLEN_PRIVSYN)
-
#define ADEDOFF_RFORK_V2 (ADEDOFF_PRIVID + ADEDLEN_PRIVID)
-#define ADEID_NUM_OSX 2
-#define ADEDOFF_FINDERI_OSX (AD_HEADER_LEN + ADEID_NUM_OSX*AD_ENTRY_LEN)
-#define ADEDOFF_RFORK_OSX (ADEDOFF_FINDERI_OSX + ADEDLEN_FINDERI)
-
-/* we keep local copies of a bunch of stuff so that we can initialize things
- * correctly. */
+/* ad:ea */
+#define ADEDOFF_FINDERI_EA (AD_HEADER_LEN + ADEID_NUM_EA * AD_ENTRY_LEN)
+#define ADEDOFF_COMMENT_EA (ADEDOFF_FINDERI_EA + ADEDLEN_FINDERI)
+#define ADEDOFF_FILEDATESI_EA (ADEDOFF_COMMENT_EA + ADEDLEN_COMMENT)
+#define ADEDOFF_AFPFILEI_EA (ADEDOFF_FILEDATESI_EA + ADEDLEN_FILEDATESI)
/* this is to prevent changing timezones from causing problems with
- localtime volumes. the screw-up is 30 years. we use a delta of 5
- years. */
+ localtime volumes. the screw-up is 30 years. we use a delta of 5 years */
#define TIMEWARP_DELTA 157680000
-
struct entry {
- u_int32_t id, offset, len;
+ uint32_t id, offset, len;
};
-static const struct entry entry_order1[ADEID_NUM_V1 +1] = {
- {ADEID_NAME, ADEDOFF_NAME_V1, ADEDLEN_INIT}, /* 3 */
- {ADEID_COMMENT, ADEDOFF_COMMENT_V1, ADEDLEN_INIT}, /* 4 */
- {ADEID_FILEI, ADEDOFF_FILEI, ADEDLEN_FILEI}, /* 7 */
- {ADEID_FINDERI, ADEDOFF_FINDERI_V1, ADEDLEN_FINDERI}, /* 9 */
- {ADEID_RFORK, ADEDOFF_RFORK_V1, ADEDLEN_INIT}, /* 2 */
- {0, 0, 0}
+/* --------------------------- */
+static uid_t default_uid = -1;
+
+/* Forward declarations */
+static int ad_mkrf(const char *path);
+static int ad_header_read(struct adouble *ad, struct stat *hst);
+static int ad_header_upgrade(struct adouble *ad, const char *name);
+
+static int ad_mkrf_ea(const char *path);
+static int ad_header_read_ea(struct adouble *ad, struct stat *hst);
+static int ad_header_upgrade_ea(struct adouble *ad, const char *name);
+
+static struct adouble_fops ad_adouble = {
+ &ad_path,
+ &ad_mkrf,
+ &ad_rebuild_adouble_header,
+ &ad_header_read,
+ &ad_header_upgrade,
+};
+
+static struct adouble_fops ad_adouble_ea = {
+ &ad_path_ea,
+ &ad_mkrf_ea,
+ &ad_rebuild_adouble_header,
+ &ad_header_read_ea,
+ &ad_header_upgrade_ea,
};
-#if AD_VERSION == AD_VERSION1
-#define DISK_EID(ad, a) (a)
+static const struct entry entry_order2[ADEID_NUM_V2 + 1] = {
+ {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT},
+ {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT},
+ {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI},
+ {ADEID_FINDERI, ADEDOFF_FINDERI_V2, ADEDLEN_FINDERI},
+ {ADEID_DID, ADEDOFF_DID, ADEDLEN_DID},
+ {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI},
+ {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT},
+ {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI},
+ {ADEID_PRIVDEV, ADEDOFF_PRIVDEV, ADEDLEN_INIT},
+ {ADEID_PRIVINO, ADEDOFF_PRIVINO, ADEDLEN_INIT},
+ {ADEID_PRIVSYN, ADEDOFF_PRIVSYN, ADEDLEN_INIT},
+ {ADEID_PRIVID, ADEDOFF_PRIVID, ADEDLEN_INIT},
+ {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT},
+ {0, 0, 0}
+};
-#else /* AD_VERSION == AD_VERSION2 */
+/* Using Extended Attributes */
+static const struct entry entry_order_ea[ADEID_NUM_EA + 1] = {
+ {ADEID_FINDERI, ADEDOFF_FINDERI_EA, ADEDLEN_FINDERI},
+ {ADEID_COMMENT, ADEDOFF_COMMENT_EA, ADEDLEN_INIT},
+ {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_EA, ADEDLEN_FILEDATESI},
+ {ADEID_AFPFILEI, ADEDOFF_AFPFILEI_EA, ADEDLEN_AFPFILEI},
+ {0, 0, 0}
+};
-static u_int32_t get_eid(struct adouble *ad, u_int32_t eid)
+static uint32_t get_eid(uint32_t eid)
{
if (eid <= 15)
return eid;
- if (ad->ad_version == AD_VERSION1)
- return 0;
if (eid == AD_DEV)
return ADEID_PRIVDEV;
if (eid == AD_INO)
return 0;
}
-#define DISK_EID(ad, a) get_eid(ad, a)
-
-static const struct entry entry_order2[ADEID_NUM_V2 +1] = {
- {ADEID_NAME, ADEDOFF_NAME_V2, ADEDLEN_INIT},
- {ADEID_COMMENT, ADEDOFF_COMMENT_V2, ADEDLEN_INIT},
- {ADEID_FILEDATESI, ADEDOFF_FILEDATESI, ADEDLEN_FILEDATESI},
- {ADEID_FINDERI, ADEDOFF_FINDERI_V2, ADEDLEN_FINDERI},
- {ADEID_DID, ADEDOFF_DID, ADEDLEN_DID},
- {ADEID_AFPFILEI, ADEDOFF_AFPFILEI, ADEDLEN_AFPFILEI},
- {ADEID_SHORTNAME, ADEDOFF_SHORTNAME, ADEDLEN_INIT},
- {ADEID_PRODOSFILEI, ADEDOFF_PRODOSFILEI, ADEDLEN_PRODOSFILEI},
- {ADEID_PRIVDEV, ADEDOFF_PRIVDEV, ADEDLEN_INIT},
- {ADEID_PRIVINO, ADEDOFF_PRIVINO, ADEDLEN_INIT},
- {ADEID_PRIVSYN, ADEDOFF_PRIVSYN, ADEDLEN_INIT},
- {ADEID_PRIVID, ADEDOFF_PRIVID, ADEDLEN_INIT},
- {ADEID_RFORK, ADEDOFF_RFORK_V2, ADEDLEN_INIT},
-
- {0, 0, 0}
-};
-
-/* OS X adouble finder info and resource fork only
- */
-static const struct entry entry_order_osx[ADEID_NUM_OSX +1] = {
- {ADEID_FINDERI, ADEDOFF_FINDERI_OSX, ADEDLEN_FINDERI},
- {ADEID_RFORK, ADEDOFF_RFORK_OSX, ADEDLEN_INIT},
-
- {0, 0, 0}
-};
-
-#define ADEID_NUM_SFM 3
-static const struct entry entry_order_sfm[ADEID_NUM_SFM +1] = {
- {ADEID_FINDERI, 16, ADEDLEN_FINDERI}, /* 9 */
- {ADEID_SFMRESERVE2, 16+32, 6}, /* 21 */
- {ADEID_FILEI, 60, ADEDLEN_FILEI}, /* 7 */
-
- {0, 0, 0}
-};
-
-#endif /* AD_VERSION == AD_VERSION2 */
-
-#if AD_VERSION == AD_VERSION2
-
-/* update a version 2 adouble resource fork with our private entries */
-static int ad_update(struct adouble *ad, const char *path)
+/* ----------------------------------- */
+static int new_ad_header(const char *path, struct adouble *ad, int adflags)
{
- struct stat st;
- u_int16_t nentries = 0;
- off_t off, shiftdata=0;
const struct entry *eid;
- static off_t entry_len[ADEID_MAX];
- static char databuf[ADEID_MAX][256], *buf;
- int fd;
- int ret = -1;
-
- /* check to see if we should convert this header. */
- if (!path || ad->ad_flags != AD_VERSION2)
- return 0;
-
- LOG(log_maxdebug, logtype_default, "ad_update: checking whether '%s' needs an upgrade.", path);
-
- if (!(ad->ad_md->adf_flags & O_RDWR)) {
- /* we were unable to open the file read write the last time */
- return 0;
- }
-
- if (ad->ad_eid[ADEID_RFORK].ade_off) {
- shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
- }
-
- memcpy(&nentries, ad->ad_data + ADEDOFF_NENTRIES, sizeof( nentries ));
- nentries = ntohs( nentries );
-
- if ( shiftdata == 0 && nentries == ADEID_NUM_V2)
- return 0;
-
- memset(entry_len, 0, sizeof(entry_len));
- memset(databuf, 0, sizeof(databuf));
-
- /* bail if we can't get a lock */
- if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0)
- goto bail_err;
-
- fd = ad->ad_md->adf_fd;
-
- if (fstat(fd, &st)) {
- goto bail_lock;
- }
-
- if (st.st_size > 0x7fffffff) {
- LOG(log_debug, logtype_default, "ad_update: file '%s' too big for update.", path);
- errno = EIO;
- goto bail_lock;
- }
-
- off = ad->ad_eid[ADEID_RFORK].ade_off;
- if (off > st.st_size) {
- LOG(log_error, logtype_default, "ad_update: invalid resource fork offset. (off: %u)", off);
- errno = EIO;
- goto bail_lock;
- }
-
- if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
- LOG(log_error, logtype_default, "ad_update: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len);
- errno = EIO;
- goto bail_lock;
- }
-
- if ((void *) (buf = (char *)
- mmap(NULL, st.st_size + shiftdata,
- PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
- MAP_FAILED) {
- goto bail_lock;
- }
-
- /* last place for failure. */
- if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
- munmap(buf, st.st_size + shiftdata);
- goto bail_lock;
- }
+ u_int16_t ashort;
+ struct stat st;
- /* move the RFORK. this assumes that the RFORK is at the end */
- if (off) {
- memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len);
+ ad->ad_magic = AD_MAGIC;
+ ad->ad_version = ad->ad_flags & 0x0f0000;
+ if (!ad->ad_version) {
+ ad->ad_version = AD_VERSION;
}
- munmap(buf, st.st_size + shiftdata);
- /* now, fix up our copy of the header */
- memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
+ memset(ad->ad_data, 0, sizeof(ad->ad_data));
- /* save the header entries */
- eid = entry_order2;
- while (eid->id) {
- if( ad->ad_eid[eid->id].ade_off != 0) {
- if ( eid->id > 2 && ad->ad_eid[eid->id].ade_len < 256)
- memcpy( databuf[eid->id], ad->ad_data +ad->ad_eid[eid->id].ade_off, ad->ad_eid[eid->id].ade_len);
- entry_len[eid->id] = ad->ad_eid[eid->id].ade_len;
- }
- eid++;
+ if (ad->ad_flags == AD_VERSION2)
+ eid = entry_order2;
+ else if (ad->ad_flags == AD_VERSION_EA)
+ eid = entry_order_ea;
+ else {
+ return -1;
}
- memset(ad->ad_data + AD_HEADER_LEN, 0, AD_DATASZ - AD_HEADER_LEN);
-
- /* copy the saved entries to the new header */
- eid = entry_order2;
while (eid->id) {
- if ( eid->id > 2 && entry_len[eid->id] > 0) {
- memcpy(ad->ad_data+eid->offset, databuf[eid->id], entry_len[eid->id]);
- }
ad->ad_eid[eid->id].ade_off = eid->offset;
- ad->ad_eid[eid->id].ade_len = entry_len[eid->id];
+ ad->ad_eid[eid->id].ade_len = eid->len;
eid++;
}
- /* rebuild the header and cleanup */
- LOG(log_debug, logtype_default, "updated AD2 header %s", path);
- ad_flush(ad );
- ret = 0;
-
-bail_lock:
- ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
-bail_err:
- return ret;
-}
-
-/* ------------------------------------------
- FIXME work only if < 2GB
-*/
-static int ad_convert(struct adouble *ad, const char *path)
-{
- struct stat st;
- u_int16_t attr;
- char *buf;
- int fd, off;
- int ret = -1;
- /* use resource fork offset from file */
- int shiftdata;
- int toV2;
- int toV1;
-
- if (!path) {
- return 0;
- }
-
- if (!(ad->ad_md->adf_flags & ( O_RDWR))) {
- /* we were unable to open the file read write the last time */
- return 0;
- }
-
- /* check to see if we should convert this header. */
- toV2 = ad->ad_version == AD_VERSION1 && ad->ad_flags == AD_VERSION2;
- toV1 = ad->ad_version == AD_VERSION2 && ad->ad_flags == AD_VERSION1;
-
- if (!toV2 && !toV1)
- return 0;
-
- /* convert from v1 to v2. what does this mean?
- * 1) change FILEI into FILEDATESI
- * 2) create space for SHORTNAME, AFPFILEI, DID, and PRODOSI
- * 3) move FILEI attributes into AFPFILEI
- * 4) initialize ACCESS field of FILEDATESI.
- * 5) move the resource fork
- */
-
- /* bail if we can't get a lock */
- if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0)
- goto bail_err;
-
- /* we reuse fd from the resource fork */
- fd = ad->ad_md->adf_fd;
-
- if (ad->ad_eid[ADEID_RFORK].ade_off) {
- shiftdata = ADEDOFF_RFORK_V2 -ad->ad_eid[ADEID_RFORK].ade_off;
- }
- else {
- shiftdata = ADEDOFF_RFORK_V2 -ADEDOFF_RFORK_V1; /* 136 */
- }
-
- if (fstat(fd, &st)) {
- goto bail_lock;
- }
-
- if (st.st_size > 0x7fffffff -shiftdata) {
- LOG(log_debug, logtype_default, "ad_v1tov2: file too big.");
- errno = EIO;
- goto bail_lock;
- }
-
- off = ad->ad_eid[ADEID_RFORK].ade_off;
-
- if (off > st.st_size) {
- LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork offset. (off: %u)", off);
- errno = EIO;
- goto bail_lock;
- }
-
- if (ad->ad_eid[ADEID_RFORK].ade_len > st.st_size - off) {
- LOG(log_error, logtype_default, "ad_v1tov2: invalid resource fork length. (rfork len: %u)", ad->ad_eid[ADEID_RFORK].ade_len);
- errno = EIO;
- goto bail_lock;
- }
-
- if ((void *) (buf = (char *)
- mmap(NULL, st.st_size + shiftdata,
- PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
- MAP_FAILED) {
- goto bail_lock;
+ /* put something sane in the directory finderinfo */
+ if ((adflags & ADFLAGS_DIR)) {
+ /* set default view */
+ ashort = htons(FINDERINFO_CLOSEDVIEW);
+ memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF, &ashort, sizeof(ashort));
+ } else {
+ /* set default creator/type fields */
+ memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
+ memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
}
- /* last place for failure. */
-
- if (sys_ftruncate(fd, st.st_size + shiftdata) < 0) {
- goto bail_lock;
+ /* make things invisible */
+ if ((ad->ad_options & ADVOL_INVDOTS) && (*path == '.')) {
+ ashort = htons(ATTRBIT_INVISIBLE);
+ ad_setattr(ad, ashort);
+ ashort = htons(FINDERINFO_INVISIBLE);
+ memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
}
- /* move the RFORK. this assumes that the RFORK is at the end */
- if (off) {
- memmove(buf + ADEDOFF_RFORK_V2, buf + off, ad->ad_eid[ADEID_RFORK].ade_len);
- }
+ if (lstat(path, &st) < 0)
+ return -1;
- munmap(buf, st.st_size + shiftdata);
-
- /* now, fix up our copy of the header */
- memset(ad->ad_filler, 0, sizeof(ad->ad_filler));
-
- /* replace FILEI with FILEDATESI */
- ad_getattr(ad, &attr);
- ad->ad_eid[ADEID_FILEDATESI].ade_off = ADEDOFF_FILEDATESI;
- ad->ad_eid[ADEID_FILEDATESI].ade_len = ADEDLEN_FILEDATESI;
- ad->ad_eid[ADEID_FILEI].ade_off = 0;
- ad->ad_eid[ADEID_FILEI].ade_len = 0;
-
- /* add in the new entries */
- ad->ad_eid[ADEID_DID].ade_off = ADEDOFF_DID;
- ad->ad_eid[ADEID_DID].ade_len = ADEDLEN_DID;
- ad->ad_eid[ADEID_AFPFILEI].ade_off = ADEDOFF_AFPFILEI;
- ad->ad_eid[ADEID_AFPFILEI].ade_len = ADEDLEN_AFPFILEI;
- ad->ad_eid[ADEID_SHORTNAME].ade_off = ADEDOFF_SHORTNAME;
- ad->ad_eid[ADEID_SHORTNAME].ade_len = ADEDLEN_INIT;
- ad->ad_eid[ADEID_PRODOSFILEI].ade_off = ADEDOFF_PRODOSFILEI;
- ad->ad_eid[ADEID_PRODOSFILEI].ade_len = ADEDLEN_PRODOSFILEI;
-
- ad->ad_eid[ADEID_PRIVDEV].ade_off = ADEDOFF_PRIVDEV;
- ad->ad_eid[ADEID_PRIVDEV].ade_len = ADEDLEN_INIT;
- ad->ad_eid[ADEID_PRIVINO].ade_off = ADEDOFF_PRIVINO;
- ad->ad_eid[ADEID_PRIVINO].ade_len = ADEDLEN_INIT;
- ad->ad_eid[ADEID_PRIVSYN].ade_off = ADEDOFF_PRIVSYN;
- ad->ad_eid[ADEID_PRIVSYN].ade_len = ADEDLEN_INIT;
- ad->ad_eid[ADEID_PRIVID].ade_off = ADEDOFF_PRIVID;
- ad->ad_eid[ADEID_PRIVID].ade_len = ADEDLEN_INIT;
-
- /* shift the old entries (NAME, COMMENT, FINDERI, RFORK) */
- ad->ad_eid[ADEID_NAME].ade_off = ADEDOFF_NAME_V2;
- ad->ad_eid[ADEID_COMMENT].ade_off = ADEDOFF_COMMENT_V2;
- ad->ad_eid[ADEID_FINDERI].ade_off = ADEDOFF_FINDERI_V2;
- ad->ad_eid[ADEID_RFORK].ade_off = ADEDOFF_RFORK_V2;
-
- /* switch to dest version */
- ad->ad_version = (toV2)?AD_VERSION2:AD_VERSION1;
-
- /* move our data buffer to make space for the new entries. */
- memmove(ad->ad_data + ADEDOFF_NAME_V2, ad->ad_data + ADEDOFF_NAME_V1,
- ADEDOFF_RFORK_V1 - ADEDOFF_NAME_V1);
-
- /* now, fill in the space with appropriate stuff. we're
- operating as a v2 file now. */
+ /* put something sane in the date fields */
+ ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
+ ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
- memset(ad_entry(ad, ADEID_DID), 0, ADEDLEN_DID);
- memset(ad_entry(ad, ADEID_AFPFILEI), 0, ADEDLEN_AFPFILEI);
- ad_setattr(ad, attr);
- memset(ad_entry(ad, ADEID_SHORTNAME), 0, ADEDLEN_SHORTNAME);
- memset(ad_entry(ad, ADEID_PRODOSFILEI), 0, ADEDLEN_PRODOSFILEI);
-
- /* rebuild the header and cleanup */
- ad_flush(ad );
- ret = 0;
-
-bail_lock:
- ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0);
-bail_err:
- return ret;
+ ad_setdate(ad, AD_DATE_BACKUP, AD_DATE_START);
+ return 0;
}
-#endif /* AD_VERSION == AD_VERSION2 */
/* -------------------------------------
read in the entries
*/
-static void parse_entries(struct adouble *ad, char *buf,
- u_int16_t nentries)
+static void parse_entries(struct adouble *ad, char *buf, uint16_t nentries)
{
- u_int32_t eid, len, off;
- int warning = 0;
+ uint32_t eid, len, off;
+ int warning = 0;
/* now, read in the entry bits */
for (; nentries > 0; nentries-- ) {
memcpy(&eid, buf, sizeof( eid ));
- eid = DISK_EID(ad, ntohl( eid ));
+ eid = get_eid(ntohl(eid));
buf += sizeof( eid );
memcpy(&off, buf, sizeof( off ));
off = ntohl( off );
buf += sizeof( len );
if (eid && eid < ADEID_MAX && off < sizeof(ad->ad_data) &&
- (off +len <= sizeof(ad->ad_data) || eid == ADEID_RFORK)) {
+ (off + len <= sizeof(ad->ad_data) || eid == ADEID_RFORK)) {
ad->ad_eid[ eid ].ade_off = off;
ad->ad_eid[ eid ].ade_len = len;
} else if (!warning) {
warning = 1;
- LOG(log_debug, logtype_default, "ad_refresh: nentries %hd eid %d",
- nentries, eid );
+ LOG(log_warning, logtype_default, "parse_entries: bogus eid: %d", eid);
}
}
}
-
/* this reads enough of the header so that we can figure out all of
* the entry lengths and offsets. once that's done, we just read/mmap
* the rest of the header in.
u_int16_t nentries;
int len;
ssize_t header_len;
- static int warning = 0;
struct stat st;
/* read the header */
memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic ));
memcpy(&ad->ad_version, buf + ADEDOFF_VERSION, sizeof( ad->ad_version ));
+ ad->ad_magic = ntohl( ad->ad_magic );
+ ad->ad_version = ntohl( ad->ad_version );
- /* tag broken v1 headers. just assume they're all right.
- * we detect two cases: null magic/version
- * byte swapped magic/version
- * XXX: in the future, you'll need the v1compat flag.
- * (ad->ad_flags & ADFLAGS_V1COMPAT) */
- if (!ad->ad_magic && !ad->ad_version) {
- if (!warning) {
- LOG(log_debug, logtype_default, "notice: fixing up null v1 magic/version.");
- warning++;
- }
- ad->ad_magic = AD_MAGIC;
- ad->ad_version = AD_VERSION1;
-
- } else if (ad->ad_magic == AD_MAGIC && ad->ad_version == AD_VERSION1) {
- if (!warning) {
- LOG(log_debug, logtype_default, "notice: fixing up byte-swapped v1 magic/version.");
- warning++;
- }
-
- } else {
- ad->ad_magic = ntohl( ad->ad_magic );
- ad->ad_version = ntohl( ad->ad_version );
- }
-
- if ((ad->ad_magic != AD_MAGIC) || ((ad->ad_version != AD_VERSION1)
-#if AD_VERSION == AD_VERSION2
- && (ad->ad_version != AD_VERSION2)
-#endif /* AD_VERSION == AD_VERSION2 */
- )) {
- LOG(log_debug, logtype_default, "ad_open: can't parse AppleDouble header.");
+ if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) {
+ LOG(log_error, logtype_default, "ad_open: can't parse AppleDouble header.");
errno = EIO;
return -1;
}
- memcpy(ad->ad_filler, buf + ADEDOFF_FILLER, sizeof( ad->ad_filler ));
memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
nentries = ntohs( nentries );
buf += AD_HEADER_LEN;
if (len > header_len - AD_HEADER_LEN) {
- LOG(log_debug, logtype_default, "ad_header_read: can't read entry info.");
+ LOG(log_error, logtype_default, "ad_header_read: can't read entry info.");
errno = EIO;
return -1;
}
if (!ad_getentryoff(ad, ADEID_RFORK)
|| (ad_getentryoff(ad, ADEID_RFORK) > sizeof(ad->ad_data))
) {
- LOG(log_debug, logtype_default, "ad_header_read: problem with rfork entry offset.");
+ LOG(log_error, logtype_default, "ad_header_read: problem with rfork entry offset.");
errno = EIO;
return -1;
}
if (ad_getentryoff(ad, ADEID_RFORK) > header_len) {
- LOG(log_debug, logtype_default, "ad_header_read: can't read in entries.");
+ LOG(log_error, logtype_default, "ad_header_read: can't read in entries.");
errno = EIO;
return -1;
}
return 1; /* fail silently */
}
}
- ad->ad_rlen = hst->st_size - ad_getentryoff(ad, ADEID_RFORK);
- /* fix up broken dates */
- if (ad->ad_version == AD_VERSION1) {
- u_int32_t aint;
-
- /* check to see if the ad date is wrong. just see if we have
- * a modification date in the future. */
- if (((ad_getdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, &aint)) == 0) &&
- (aint > TIMEWARP_DELTA + hst->st_mtime)) {
- ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, aint - AD_DATE_DELTA);
- ad_getdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, &aint);
- ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, aint - AD_DATE_DELTA);
- ad_getdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, &aint);
- ad_setdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, aint - AD_DATE_DELTA);
- }
- }
+ ad->ad_rlen = hst->st_size - ad_getentryoff(ad, ADEID_RFORK);
return 0;
}
-/* ---------------------------
- SFM structure
-*/
-#if 0
-typedef struct {
- byte afpi_Signature[4]; /* Must be 0x00504641 */
- byte afpi_Version[4]; /* Must be 0x00010000 */
- byte afpi_Reserved1[4];
- byte afpi_BackupTime[4]; /* Backup time for the file/dir */
- byte finderinfo[32]; /* Finder info */
- byte afpi_ProDosInfo[6]; /* ProDos Info */
- byte afpi_Reserved2[6];
-} sfm_info;
-#endif
-
-static int ad_header_sfm_read(struct adouble *ad, struct stat *hst)
+static int ad_header_read_ea(struct adouble *ad, struct stat *hst _U_)
{
- char *buf = ad->ad_data;
- const struct entry *eid;
- ssize_t header_len;
- struct stat st;
+ uint16_t nentries;
+ int len;
+ ssize_t header_len;
+ char *buf = ad->ad_data;
/* read the header */
- if ((header_len = adf_pread( ad->ad_md, buf, sizeof(ad->ad_data), 0)) < 0) {
+ if ((header_len = sys_lgetxattr(cfrombstr(ad->ad_fullpath), AD_EA_META, ad->ad_data, AD_DATASZ_EA)) < 1) {
+ LOG(log_debug, logtype_default, "ad_header_read_ea: %s (%u)", strerror(errno), errno);
return -1;
}
- if (header_len != AD_SFM_LEN) {
+
+ if (header_len < AD_HEADER_LEN) {
+ LOG(log_error, logtype_default, "ad_header_read_ea: bogus AppleDouble header.");
errno = EIO;
return -1;
}
memcpy(&ad->ad_magic, buf, sizeof( ad->ad_magic ));
- memcpy(&ad->ad_version, buf + 4, sizeof( ad->ad_version ));
-
- /* FIXME in the great Microsoft tradition they aren't in network order */
-#if 0
- if (ad->ad_magic == SFM_MAGIC && ad->ad_version == AD_VERSION1) {
- static int warning = 0;
- if (!warning) {
- LOG(log_debug, logtype_default, "notice: fixing up byte-swapped v1 magic/version.");
- warning++;
- }
+ memcpy(&ad->ad_version, buf + ADEDOFF_VERSION, sizeof( ad->ad_version ));
- } else {
- ad->ad_magic = ntohl( ad->ad_magic );
- ad->ad_version = ntohl( ad->ad_version );
- }
-#endif
- if ((ad->ad_magic != SFM_MAGIC) || ((ad->ad_version != AD_VERSION1) )) {
+ ad->ad_magic = ntohl( ad->ad_magic );
+ ad->ad_version = ntohl( ad->ad_version );
+
+ if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) {
+ LOG(log_error, logtype_default, "ad_header_read_ea: wrong magic or version");
errno = EIO;
- LOG(log_debug, logtype_default, "ad_header_sfm_read: can't parse AppleDouble header.");
return -1;
}
- /* reinit adouble table */
- eid = entry_order_sfm;
- while (eid->id) {
- ad->ad_eid[eid->id].ade_off = eid->offset;
- ad->ad_eid[eid->id].ade_len = eid->len;
- eid++;
- }
-
- /* steal some prodos for attribute */
- {
+ memcpy(&nentries, buf + ADEDOFF_NENTRIES, sizeof( nentries ));
+ nentries = ntohs( nentries );
- u_int16_t attribute;
- memcpy(&attribute, buf + 48 +4, sizeof(attribute));
- ad_setattr(ad, attribute );
+ /* Protect against bogus nentries */
+ len = nentries * AD_ENTRY_LEN;
+ if (len + AD_HEADER_LEN > sizeof(ad->ad_data))
+ len = sizeof(ad->ad_data) - AD_HEADER_LEN;
+ if (len > header_len - AD_HEADER_LEN) {
+ LOG(log_error, logtype_default, "ad_header_read_ea: can't read entry info.");
+ errno = EIO;
+ return -1;
}
+ nentries = len / AD_ENTRY_LEN;
- if (ad->ad_resource_fork.adf_fd != -1) {
- /* we have a resource fork use it rather than the metadata */
- if (fstat(ad->ad_resource_fork.adf_fd, &st) < 0) {
- /* XXX set to zero ?
- ad->ad_rlen = 0;
- */
- return 1;
- }
- ad->ad_rlen = st.st_size;
- hst = &st;
- }
- else if (hst == NULL) {
- hst = &st;
- if (fstat(ad->ad_md->adf_fd, &st) < 0) {
- return 1; /* fail silently */
- }
- }
+ /* Now parse entries */
+ parse_entries(ad, buf + AD_HEADER_LEN, nentries);
+ return 0;
+}
- /* fix up broken dates */
- if (ad->ad_version == AD_VERSION1) {
- u_int32_t aint;
-
- /* check to see if the ad date is wrong. just see if we have
- * a modification date in the future. */
- if (((ad_getdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, &aint)) == 0) &&
- (aint > TIMEWARP_DELTA + hst->st_mtime)) {
- ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, aint - AD_DATE_DELTA);
- ad_getdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, &aint);
- ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, aint - AD_DATE_DELTA);
- ad_getdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, &aint);
- ad_setdate(ad, AD_DATE_BACKUP | AD_DATE_UNIX, aint - AD_DATE_DELTA);
- }
+static int ad_mkrf(const char *path)
+{
+ char *slash;
+ /*
+ * Probably .AppleDouble doesn't exist, try to mkdir it.
+ */
+ if (NULL == ( slash = strrchr( path, '/' )) ) {
+ return -1;
}
-
+ *slash = '\0';
+ errno = 0;
+ if ( ad_mkdir( path, 0777 ) < 0 ) {
+ return -1;
+ }
+ *slash = '/';
return 0;
}
-/* ---------------------------------------
- * Put the .AppleDouble where it needs to be:
- *
- * / a/.AppleDouble/b
- * a/b
- * \ b/.AppleDouble/.Parent
- *
- * FIXME: should do something for pathname > MAXPATHLEN
- */
-char *
-ad_path( const char *path, int adflags)
+static int ad_mkrf_ea(const char *path _U_)
{
- static char pathbuf[ MAXPATHLEN + 1];
- const char *slash;
- size_t l ;
+ AFP_PANIC("ad_mkrf_ea: dont use");
+ return 0;
+}
- if ( adflags & ADFLAGS_DIR ) {
- l = strlcpy( pathbuf, path, sizeof(pathbuf));
+/* ----------------
+ if we are root change path user/ group
+ It can be a native function for BSD cf. FAQ.Q10
+ path: pathname to chown
+ stbuf: parent directory inode
- if ( l && l < MAXPATHLEN) {
- pathbuf[l++] = '/';
+ use fstat and fchown or lchown with linux?
+*/
+#define EMULATE_SUIDDIR
+
+static int ad_chown(const char *path, struct stat *stbuf)
+{
+ int ret = 0;
+#ifdef EMULATE_SUIDDIR
+ uid_t id;
+
+ if (default_uid != (uid_t)-1) {
+ /* we are root (admin) */
+ id = (default_uid)?default_uid:stbuf->st_uid;
+ ret = lchown( path, id, stbuf->st_gid );
+ }
+#endif
+ return ret;
+}
+
+#define DEFMASK 07700 /* be conservative */
+
+/* ----------------
+ return access right and inode of path parent directory
+*/
+static int ad_mode_st(const char *path, int *mode, struct stat *stbuf)
+{
+ if (*mode == 0) {
+ return -1;
+ }
+ if (ad_stat(path, stbuf) != 0) {
+ *mode &= DEFMASK;
+ return -1;
+ }
+ *mode &= stbuf->st_mode;
+ return 0;
+}
+
+/* --------------------------- */
+static int ad_header_upgrade(struct adouble *ad _U_, const char *name _U_)
+{
+ return 0;
+}
+
+static int ad_header_upgrade_ea(struct adouble *ad _U_, const char *name _U_)
+{
+ AFP_PANIC("ad_header_upgrade_ea: dont use");
+ return 0;
+}
+
+static int ad_open_df(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+{
+ struct stat st_dir;
+ int hoflags, admode;
+ int st_invalid = -1;
+
+ LOG(log_maxdebug, logtype_default, "ad_open_df(\"%s/%s\", adf: 0x%04x, of: 0x%04x)",
+ getcwdpath(), path, adflags, oflags);
+
+ if (ad_data_fileno(ad) == -1) {
+ hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+ admode = mode;
+ if ((oflags & O_CREAT)) {
+ st_invalid = ad_mode_st(path, &admode, &st_dir);
+ if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+ admode = mode;
+ }
+ }
+
+ ad->ad_data_fork.adf_fd = open(path, hoflags | O_NOFOLLOW, admode);
+
+ if (ad->ad_data_fork.adf_fd == -1) {
+ if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
+ hoflags = oflags;
+ ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode );
+ }
+ if (ad->ad_data_fork.adf_fd == -1 && errno == OPEN_NOFOLLOW_ERRNO) {
+ int lsz;
+
+ ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
+ lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN);
+ if (lsz <= 0) {
+ free(ad->ad_data_fork.adf_syml);
+ return -1;
+ }
+ ad->ad_data_fork.adf_syml[lsz] = 0;
+ ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
+ }
+ }
+
+ if ( ad->ad_data_fork.adf_fd == -1 )
+ return -1;
+
+ AD_SET(ad->ad_data_fork.adf_off);
+ ad->ad_data_fork.adf_flags = hoflags;
+ if (!st_invalid) {
+ /* just created, set owner if admin (root) */
+ ad_chown(path, &st_dir);
}
- strlcpy(pathbuf +l, ".AppleDouble/.Parent", sizeof(pathbuf) -l);
} else {
- if (NULL != ( slash = strrchr( path, '/' )) ) {
- slash++;
- l = slash - path;
- /* XXX we must return NULL here and test in the caller */
- if (l > MAXPATHLEN)
- l = MAXPATHLEN;
- memcpy( pathbuf, path, l);
- } else {
- l = 0;
- slash = path;
+ /* the file is already open... but */
+ if ((oflags & ( O_RDWR | O_WRONLY))
+ /* we want write access */
+ && !(ad->ad_data_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
+ /* and it was denied the first time */
+ errno = EACCES;
+ return -1;
}
- l += strlcpy( pathbuf +l, ".AppleDouble/", sizeof(pathbuf) -l);
- strlcpy( pathbuf + l, slash, sizeof(pathbuf) -l);
+ /* FIXME
+ * for now ad_open is never called with O_TRUNC or O_EXCL if the file is
+ * already open. Should we check for it? ie
+ * O_EXCL --> error
+ * O_TRUNC --> truncate the fork.
+ * idem for ressource fork.
+ */
}
- return( pathbuf );
+ return 0;
}
-/* -------------------- */
-static int ad_mkrf(char *path)
+static int ad_open_hf_v2(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
{
- char *slash;
- /*
- * Probably .AppleDouble doesn't exist, try to mkdir it.
- */
- if (NULL == ( slash = strrchr( path, '/' )) ) {
- return -1;
+ struct stat st_dir;
+ struct stat st_meta;
+ struct stat *pst = NULL;
+ const char *ad_p;
+ int hoflags, admode;
+ int st_invalid = -1;
+
+ ad_p = ad->ad_ops->ad_path( path, adflags );
+
+ hoflags = (oflags & ~(O_CREAT | O_EXCL)) | O_NOFOLLOW;
+
+ ad->ad_md->adf_fd = open(ad_p, hoflags, 0);
+
+ if ( ad->ad_md->adf_fd < 0 ) {
+ if (errno == ENOENT && (oflags & O_CREAT) ) {
+ /*
+ * We're expecting to create a new adouble header file here
+ * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
+ */
+ LOG(log_debug, logtype_default, "ad_open(\"%s\"): creating adouble file",
+ abspath(path));
+ admode = mode;
+ errno = 0;
+ st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
+ if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+ admode = mode;
+ }
+ admode = ad_hf_mode(admode);
+ if ((errno == ENOENT)) {
+ if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
+ return -1;
+ }
+ admode = mode;
+ st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
+ if ((ad->ad_options & ADVOL_UNIXPRIV)) {
+ admode = mode;
+ }
+ admode = ad_hf_mode(admode);
+ }
+ /* retry with O_CREAT */
+ ad->ad_md->adf_fd = open(ad_p, oflags, admode);
+ if ( ad->ad_md->adf_fd < 0 ) {
+ return -1;
+ }
+ ad->ad_md->adf_flags = oflags;
+ /* just created, set owner if admin owner (root) */
+ if (!st_invalid) {
+ ad_chown(ad_p, &st_dir);
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ ad->ad_md->adf_flags = hoflags;
+ if (fstat(ad->ad_md->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) {
+ /* for 0 length files, treat them as new. */
+ ad->ad_md->adf_flags |= O_TRUNC;
+ } else {
+ /* we have valid data in st_meta stat structure, reused it in ad_header_read */
+ pst = &st_meta;
+ }
}
- *slash = '\0';
- errno = 0;
- if ( ad_mkdir( path, 0777 ) < 0 ) {
+ AD_SET(ad->ad_md->adf_off);
+
+ if ((ad->ad_md->adf_flags & ( O_TRUNC | O_CREAT ))) {
+ /* This is a new adouble header file, create it */
+ if (new_ad_header(path, ad, adflags) < 0) {
+ int err = errno;
+ /* the file is already deleted, perm, whatever, so return an error */
+ errno = err;
+ return -1;
+ }
+ ad_flush(ad);
+ } else {
+ /* Read the adouble header in and parse it.*/
+ if (ad->ad_ops->ad_header_read( ad , pst) < 0
+ || ad->ad_ops->ad_header_upgrade(ad, ad_p) < 0) {
+ int err = errno;
+ errno = err;
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int ad_open_hf_ea(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+{
+ ssize_t rforklen;
+ int ret;
+
+ LOG(log_maxdebug, logtype_default, "ad_open_hf_ea(\"%s\", adf: 0x%04x, of: 0x%04x)",
+ abspath(path), adflags, oflags);
+
+ if ((ad->ad_md->adf_fd = open(path, O_RDONLY | O_NOFOLLOW)) == -1)
return -1;
+
+ /* Read the adouble header in and parse it.*/
+ if (ad->ad_ops->ad_header_read(ad, NULL) != 0) {
+ if (!(oflags & O_CREAT))
+ return -1;
+
+ /* It doesnt exist, EPERM or another error */
+ if (errno != ENOATTR && errno != ENOENT) {
+ LOG(log_error, logtype_default, "ad_open_hf_ea: unexpected: %s", strerror(errno));
+ ret = -1;
+ goto error;
+ }
+
+ /* Create one */
+ if (new_ad_header(path, ad, adflags) < 0) {
+ LOG(log_error, logtype_default, "ad_open_hf_ea: can't create new header: %s",
+ abspath(path));
+ ret = -1;
+ goto error;
+ }
+
+ ad_flush(ad);
}
- *slash = '/';
+
+ ad->ad_md->adf_flags = O_RDWR; /* Pretend its rw, in fact for the EA API it is */
+
+ if ((rforklen = sys_lgetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, NULL, 0)) > 0)
+ ad->ad_rlen = rforklen;
+
return 0;
+
+error:
+ return ret;
+}
+
+static int ad_open_hf(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+{
+ int ret = 0;
+
+ LOG(log_maxdebug, logtype_default, "ad_open_hf(\"%s/%s\", adf: 0x%04x, of: 0x%04x)",
+ getcwdpath(), path, adflags, oflags);
+
+ memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
+ ad->ad_rlen = 0;
+
+ switch (ad->ad_flags) {
+ case AD_VERSION2:
+ ret = ad_open_hf_v2(path, adflags, oflags, mode, ad);
+ break;
+ case AD_VERSION_EA:
+ ret = ad_open_hf_ea(path, adflags, oflags, mode, ad);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
}
-/* ---------------------------------------
- * Put the resource fork where it needs to be:
- * ._name
+/*!
+ * Open EA with resfork, only for AD_VERSION_EA, a nullop otherwise
*/
-char *
-ad_path_osx(const char *path, int adflags _U_)
+static int ad_open_rf(const char *path, int adflags, int oflags, int mode, struct adouble *ad)
{
- static char pathbuf[ MAXPATHLEN + 1];
- char c, *slash, buf[MAXPATHLEN + 1];
+ int ret = 0;
+
+ if (ad->ad_flags != AD_VERSION_EA)
+ return 0;
- if (!strcmp(path,".")) {
- /* fixme */
- getcwd(buf, MAXPATHLEN);
+ LOG(log_debug, logtype_default, "ad_open_rf(\"%s\", adf: 0x%04x, of: 0x%04x)",
+ abspath(path), adflags, oflags);
+
+ if ((ad->ad_rlen = sys_lgetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, NULL, 0)) <= 0) {
+ switch (errno) {
+ case ENOATTR:
+ ad->ad_rlen = 0;
+ break;
+ default:
+ LOG(log_warning, logtype_default, "ad_open_rf(\"%s\"): %s",
+ abspath(path), strerror(errno));
+ ret = -1;
+ goto exit;
+ }
}
- else {
- strlcpy(buf, path, MAXPATHLEN +1);
+
+ /* Round up and allocate buffer */
+ size_t roundup = ((ad->ad_rlen / RFORK_EA_ALLOCSIZE) + 1) * RFORK_EA_ALLOCSIZE;
+ if ((ad->ad_resforkbuf = malloc(roundup)) == NULL) {
+ ret = -1;
+ goto exit;
}
- if (NULL != ( slash = strrchr( buf, '/' )) ) {
- c = *++slash;
- *slash = '\0';
- strlcpy( pathbuf, buf, MAXPATHLEN +1);
- *slash = c;
- } else {
- pathbuf[ 0 ] = '\0';
- slash = buf;
+
+ ad->ad_resforkbufsize = roundup;
+
+ /* Read the EA into the buffer */
+ if (ad->ad_rlen > 0) {
+ if (sys_lgetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, ad->ad_resforkbuf, ad->ad_rlen) == -1) {
+ ret = -1;
+ goto exit;
+ }
+ }
+
+exit:
+ if (ret != 0) {
+ free(ad->ad_resforkbuf);
+ ad->ad_resforkbuf = NULL;
+ ad->ad_rlen = 0;
+ ad->ad_resforkbufsize = 0;
}
- strlcat( pathbuf, "._", MAXPATHLEN +1);
- strlcat( pathbuf, slash, MAXPATHLEN +1);
- return pathbuf;
+
+ return ret;
}
-/* -------------------- */
-static int ad_mkrf_osx(char *path _U_)
+
+/***********************************************************************************
+ * API functions
+ ********************************************************************************* */
+
+const char *ad_path_ea( const char *path, int adflags _U_)
{
- return 0;
+ return path;
}
-/* ---------------------------------------
+/*
* Put the .AppleDouble where it needs to be:
*
- * / a/.AppleDouble/b/AFP_AfpInfo
+ * / a/.AppleDouble/b
* a/b
- * \ b/.AppleDouble/.Parent/AFP_AfpInfo
+ * \ b/.AppleDouble/.Parent
*
+ * FIXME: should do something for pathname > MAXPATHLEN
*/
-char *
-ad_path_sfm( const char *path, int adflags)
+const char *ad_path( const char *path, int adflags)
{
static char pathbuf[ MAXPATHLEN + 1];
- char c, *slash, buf[MAXPATHLEN + 1];
- size_t l;
+ const char *slash;
+ size_t l ;
- l = strlcpy(buf, path, MAXPATHLEN +1);
if ( adflags & ADFLAGS_DIR ) {
- strcpy( pathbuf, buf);
- if ( *buf != '\0' && l < MAXPATHLEN) {
+ l = strlcpy( pathbuf, path, sizeof(pathbuf));
+
+ if ( l && l < MAXPATHLEN) {
pathbuf[l++] = '/';
- pathbuf[l] = 0;
}
- slash = ".Parent";
+ strlcpy(pathbuf +l, ".AppleDouble/.Parent", sizeof(pathbuf) -l);
} else {
- if (NULL != ( slash = strrchr( buf, '/' )) ) {
- c = *++slash;
- *slash = '\0';
- strcpy( pathbuf, buf);
- *slash = c;
+ if (NULL != ( slash = strrchr( path, '/' )) ) {
+ slash++;
+ l = slash - path;
+ /* XXX we must return NULL here and test in the caller */
+ if (l > MAXPATHLEN)
+ l = MAXPATHLEN;
+ memcpy( pathbuf, path, l);
} else {
- pathbuf[ 0 ] = '\0';
- slash = buf;
+ l = 0;
+ slash = path;
}
+ l += strlcpy( pathbuf +l, ".AppleDouble/", sizeof(pathbuf) -l);
+ strlcpy( pathbuf + l, slash, sizeof(pathbuf) -l);
}
- strlcat( pathbuf, ".AppleDouble/", MAXPATHLEN +1);
- strlcat( pathbuf, slash, MAXPATHLEN +1);
- if ((adflags == ADFLAGS_RF)) {
- strlcat( pathbuf, "/AFP_Resource", MAXPATHLEN +1);
- }
- else {
- strlcat( pathbuf, "/AFP_AfpInfo", MAXPATHLEN +1);
- }
return( pathbuf );
}
-/* -------------------- */
-static int ad_mkrf_sfm(char *path)
-{
- char *slash;
- /*
- * Probably .AppleDouble doesn't exist, try to mkdir it.
- */
- if (NULL == ( slash = strrchr( path, '/' )) ) {
- return -1;
- }
- *slash = 0;
- errno = 0;
- if ( ad_mkdir( path, 0777 ) < 0 ) {
- if ( errno == ENOENT ) {
- char *slash1;
-
- if (NULL == ( slash1 = strrchr( path, '/' )) )
- return -1;
- errno = 0;
- *slash1 = 0;
- if ( ad_mkdir( path, 0777 ) < 0 )
- return -1;
- *slash1 = '/';
- if ( ad_mkdir( path, 0777 ) < 0 )
- return -1;
- }
- else
- return -1;
- }
- *slash = '/';
- return 0;
-}
-
/* -------------------------
* Support inherited protection modes for AppleDouble files. The supplied
* mode is ANDed with the parent directory's mask value in lieu of "umask",
* and that value is returned.
*/
-
-#define DEFMASK 07700 /* be conservative */
-
-char
-*ad_dir(const char *path)
+char *ad_dir(const char *path)
{
static char modebuf[ MAXPATHLEN + 1];
char *slash;
return modebuf;
}
-/* ---------------- */
-static uid_t default_uid = -1;
-
int ad_setfuid(const uid_t id)
{
default_uid = id;
/* ---------------- */
uid_t ad_getfuid(void)
{
- return default_uid;
-}
-
-/* ----------------
- return inode of path parent directory
-*/
-int ad_stat(const char *path, struct stat *stbuf)
-{
- char *p;
-
- p = ad_dir(path);
- if (!p) {
- return -1;
- }
-//FIXME!
- return lstat( p, stbuf );
-}
-
-/* ----------------
- if we are root change path user/ group
- It can be a native function for BSD cf. FAQ.Q10
- path: pathname to chown
- stbuf: parent directory inode
-
- use fstat and fchown or lchown with linux?
-*/
-#define EMULATE_SUIDDIR
-
-static int ad_chown(const char *path, struct stat *stbuf)
-{
- int ret = 0;
-#ifdef EMULATE_SUIDDIR
- uid_t id;
-
- if (default_uid != (uid_t)-1) {
- /* we are root (admin) */
- id = (default_uid)?default_uid:stbuf->st_uid;
- ret = lchown( path, id, stbuf->st_gid );
- }
-#endif
- return ret;
-}
-
-/* ----------------
- return access right and inode of path parent directory
-*/
-static int ad_mode_st(const char *path, int *mode, struct stat *stbuf)
-{
- if (*mode == 0) {
- return -1;
- }
- if (ad_stat(path, stbuf) != 0) {
- *mode &= DEFMASK;
- return -1;
- }
- *mode &= stbuf->st_mode;
- return 0;
-}
-
-/* ----------------
- return access right of path parent directory
-*/
-int
-ad_mode( const char *path, int mode)
-{
- struct stat stbuf;
- ad_mode_st(path, &mode, &stbuf);
- return mode;
-}
-
-/*
- * Use mkdir() with mode bits taken from ad_mode().
- */
-int
-ad_mkdir( const char *path, int mode)
-{
- int ret;
- int st_invalid;
- struct stat stbuf;
-
- LOG(log_debug, logtype_default, "ad_mkdir(\"%s\", %04o) {cwd: \"%s\"}",
- path, mode, getcwdpath());
-
- st_invalid = ad_mode_st(path, &mode, &stbuf);
- ret = mkdir( path, mode );
- if (ret || st_invalid)
- return ret;
- ad_chown(path, &stbuf);
-
- return ret;
-}
-
-/* ----------------- */
-static int ad_error(struct adouble *ad, int adflags)
-{
- int err = errno;
- if ((adflags & ADFLAGS_NOHF)) {
- /* FIXME double check : set header offset ?*/
- return 0;
- }
- if ((adflags & ADFLAGS_DF)) {
- ad_close( ad, ADFLAGS_DF );
- err = errno;
- }
- return -1 ;
-}
-
-static int new_rfork(const char *path, struct adouble *ad, int adflags);
-
-#ifdef HAVE_PREAD
-#define AD_SET(a)
-#else
-#define AD_SET(a) a = 0
-#endif
-
-/* --------------------------- */
-static int ad_check_size(struct adouble *ad _U_, struct stat *st)
-{
- if (st->st_size > 0 && st->st_size < AD_DATASZ1)
- return 1;
- return 0;
-}
-
-/* --------------------------- */
-static int ad_check_size_sfm(struct adouble *ad _U_, struct stat *st)
-{
- if (st->st_size > 0 && st->st_size < AD_SFM_LEN)
- return 1;
- return 0;
-}
-
-/* --------------------------- */
-static int ad_header_upgrade(struct adouble *ad, char *name)
-{
-#if AD_VERSION == AD_VERSION2
- int ret;
- if ( (ret = ad_convert(ad, name)) < 0 || (ret = ad_update(ad, name) < 0)) {
- return ret;
- }
-#endif
- return 0;
-}
-
-/* --------------------------- */
-static int ad_header_upgrade_none(struct adouble *ad _U_, char *name _U_)
-{
- return 0;
+ return default_uid;
}
-/* --------------------------- */
-static struct adouble_fops ad_osx = {
- &ad_path_osx,
- &ad_mkrf_osx,
- &ad_rebuild_adouble_header,
- &ad_check_size,
+/* ----------------
+ stat path parent directory
+*/
+int ad_stat(const char *path, struct stat *stbuf)
+{
+ char *p;
- &ad_header_read,
- &ad_header_upgrade,
-};
+ p = ad_dir(path);
+ if (!p)
+ return -1;
+ return lstat( p, stbuf );
+}
-static struct adouble_fops ad_sfm = {
- &ad_path_sfm,
- &ad_mkrf_sfm,
- &ad_rebuild_sfm_header,
- &ad_check_size_sfm,
+/* ----------------
+ return access right of path parent directory
+*/
+int ad_mode( const char *path, int mode)
+{
+ struct stat stbuf;
+ ad_mode_st(path, &mode, &stbuf);
+ return mode;
+}
- &ad_header_sfm_read,
- &ad_header_upgrade_none,
-};
+/*
+ * Use mkdir() with mode bits taken from ad_mode().
+ */
+int ad_mkdir( const char *path, int mode)
+{
+ int ret;
+ int st_invalid;
+ struct stat stbuf;
-static struct adouble_fops ad_adouble = {
- &ad_path,
- &ad_mkrf,
- &ad_rebuild_adouble_header,
- &ad_check_size,
+ LOG(log_debug, logtype_default, "ad_mkdir(\"%s\", %04o) {cwd: \"%s\"}",
+ path, mode, getcwdpath());
- &ad_header_read,
- &ad_header_upgrade,
-};
+ st_invalid = ad_mode_st(path, &mode, &stbuf);
+ ret = mkdir( path, mode );
+ if (ret || st_invalid)
+ return ret;
+ ad_chown(path, &stbuf);
+ return ret;
+}
void ad_init(struct adouble *ad, int flags, int options)
{
- ad->ad_inited = 0;
- ad->ad_flags = flags;
- if (flags == AD_VERSION2_OSX) {
- ad->ad_ops = &ad_osx;
+ memset(ad, 0, sizeof(struct adouble));
+
+ if (flags == AD_VERSION2) {
+ ad->ad_ops = &ad_adouble;
ad->ad_md = &ad->ad_resource_fork;
}
- else if (flags == AD_VERSION1_SFM) {
- ad->ad_ops = &ad_sfm;
+ else if (flags == AD_VERSION_EA) {
+ ad->ad_ops = &ad_adouble_ea;
ad->ad_md = &ad->ad_metadata_fork;
+ } else {
+ LOG(log_error, logtype_default, "ad_init: unknown AD version");
+ errno = EIO;
+ return;
}
- else {
- ad->ad_ops = &ad_adouble;
- ad->ad_md = &ad->ad_resource_fork;
- }
- ad->ad_options = options;
+ ad->ad_flags = flags;
+ ad->ad_options = options;
ad_data_fileno(ad) = -1;
ad_reso_fileno(ad) = -1;
ad_meta_fileno(ad) = -1;
- /* following can be read even if there's no
- * meda data.
- */
- memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
- ad->ad_rlen = 0;
+ ad->ad_inited = AD_INITED;
+}
+
+const char *adflags2logstr(int adflags)
+{
+ int first = 1;
+ static char buf[64];
+
+ buf[0] = 0;
+
+ if (adflags & ADFLAGS_DF) {
+ strlcat(buf, "DF", 64);
+ first = 0;
+ }
+ if (adflags & ADFLAGS_RF) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "RF", 64);
+ first = 0;
+ }
+ if (adflags & ADFLAGS_HF) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "HF", 64);
+ first = 0;
+ }
+ if (adflags & ADFLAGS_NOHF) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "NOHF", 64);
+ first = 0;
+ }
+ if (adflags & ADFLAGS_DIR) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "DIR", 64);
+ first = 0;
+ }
+ if (adflags & ADFLAGS_OPENFORKS) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "OF", 64);
+ first = 0;
+ }
+ return buf;
+}
+
+const char *oflags2logstr(int oflags)
+{
+ int first = 1;
+ static char buf[64];
+
+ buf[0] = 0;
+
+ if (oflags == O_RDONLY) {
+ strlcat(buf, "O_RDONLY", 64);
+ first = 0;
+ }
+ if (oflags & O_RDWR) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "O_RDWR", 64);
+ first = 0;
+ }
+ if (oflags & O_CREAT) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "O_CREAT", 64);
+ first = 0;
+ }
+ if (oflags & O_EXCL) {
+ if (!first)
+ strlcat(buf, "|", 64);
+ strlcat(buf, "O_EXCL", 64);
+ first = 0;
+ }
+ return buf;
}
/*!
* ad_init(&ad, vol->v_adouble, vol->v_ad_options);
* @endcode
*
- * @param path Path to file or directory
- *
- * @param adflags ADFLAGS_DF: open data file/fork\n
- * ADFLAGS_HF: open header (metadata) file\n
- * ADFLAGS_RF: open ressource fork *** FIXME: not used ?! *** \n
- * ADFLAGS_CREATE: indicate creation\n
- * ADFLAGS_NOHF: it's not an error if header file couldn't be created\n
- * ADFLAGS_DIR: if path is a directory you MUST or ADFLAGS_DIR to adflags\n
- * ADFLAGS_NOADOUBLE: dont create adouble files if not necessary\n
- * ADFLAGS_RDONLY: open read only\n
- * ADFLAGS_OPENFORKS: check for open forks from other processes\n
- * ADFLAGS_MD: alias for ADFLAGS_HF\n
- * ADFLAGS_V1COMPAT: obsolete
+ * Open a files data fork, metadata fork or ressource fork.
+ * For each fork to be opened specify the open flags and mode in case you want to create it
+ * (O_CREAT in open flags). The order in which forks are opened is:
+ * 1. ADFLAGS_DF
+ * 2. ADFLAGS_HF
+ * 3. ADFLAGS_RF
+ * The variable arguments must be passed according to this order.
*
- * @param oflags flags passed through to open syscall: \n
- * O_RDONLY: *** FIXME *** \n
- * O_RDWR: *** FIXME *** \n
- * O_CREAT: create fork\n
- * O_EXCL: fail if exists with O_CREAT
+ * @param ad (rw) pointer to struct adouble
+ * @param path (r) Path to file or directory
+ * @param adflags (r) ADFLAGS_DF: open data fork \n
+ * ADFLAGS_RF: open ressource fork \n
+ * ADFLAGS_HF: open header (metadata) file \n
+ * ADFLAGS_NOHF: it's not an error if header file couldn't be created \n
+ * ADFLAGS_DIR: if path is a directory you MUST or ADFLAGS_DIR to adflags \n
+ * ADFLAGS_RDONLY: dont upgrade mode from r to rw with adouble:v2 headerfile \n
+ * ADFLAGS_OPENFORKS: check for open forks from other processes
*
- * @param mode passed to open with O_CREAT
- *
- * @param ad pointer to struct adouble
- *
- * @returns 0 on success
- *
- * @note It's not possible to open the header file O_RDONLY -- the read
- * will fail and return an error. this refcounts things now.\n
- * metadata(ressource)-fork only gets created with O_CREAT.
+ * @returns 0 on success, any other value indicates an error
*/
-int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble *ad)
+static int vad_open(struct adouble *ad, const char *path, int adflags, va_list args)
{
- struct stat st_dir;
- struct stat st_meta;
- struct stat *pst = NULL;
- char *ad_p;
- int hoflags, admode;
- int st_invalid = -1;
- int open_df = 0;
-
- if (ad->ad_inited != AD_INITED) {
- ad->ad_inited = AD_INITED;
- ad->ad_refcount = 1;
- ad->ad_open_forks = 0;
- ad->ad_adflags = adflags;
- ad->ad_resource_fork.adf_refcount = 0;
- ad->ad_data_fork.adf_refcount = 0;
- ad->ad_data_fork.adf_syml=0;
- }
- else {
- ad->ad_open_forks = ((ad->ad_data_fork.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
- /* XXX not true if we have a meta data fork ? */
- if ((ad->ad_resource_fork.adf_refcount > ad->ad_data_fork.adf_refcount))
- ad->ad_open_forks |= ATTRBIT_ROPEN;
- }
-
- if ((adflags & ADFLAGS_DF)) {
- if (ad_data_fileno(ad) == -1) {
- hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
- admode = mode;
- if ((oflags & O_CREAT)) {
- st_invalid = ad_mode_st(path, &admode, &st_dir);
- if ((ad->ad_options & ADVOL_UNIXPRIV)) {
- admode = mode;
- }
- }
-
- ad->ad_data_fork.adf_fd =open( path, hoflags | O_NOFOLLOW, admode );
-
- if (ad->ad_data_fork.adf_fd == -1) {
- if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
- hoflags = oflags;
- ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode );
- }
- if (ad->ad_data_fork.adf_fd == -1 && errno == OPEN_NOFOLLOW_ERRNO) {
- int lsz;
-
- ad->ad_data_fork.adf_syml = malloc(MAXPATHLEN+1);
- lsz = readlink(path, ad->ad_data_fork.adf_syml, MAXPATHLEN);
- if (lsz <= 0) {
- free(ad->ad_data_fork.adf_syml);
- return -1;
- }
- ad->ad_data_fork.adf_syml[lsz] = 0;
- ad->ad_data_fork.adf_fd = -2; /* -2 means its a symlink */
- }
- }
-
- if ( ad->ad_data_fork.adf_fd == -1 )
- return -1;
-
- AD_SET(ad->ad_data_fork.adf_off);
- ad->ad_data_fork.adf_flags = hoflags;
- if (!st_invalid) {
- /* just created, set owner if admin (root) */
- ad_chown(path, &st_dir);
- }
- adf_lock_init(&ad->ad_data_fork);
- }
- else {
- /* the file is already open... but */
- if ((oflags & ( O_RDWR | O_WRONLY)) && /* we want write access */
- !(ad->ad_data_fork.adf_flags & ( O_RDWR | O_WRONLY))) /* and it was denied the first time */
- {
- errno = EACCES;
- return -1;
- }
- /* FIXME
- * for now ad_open is never called with O_TRUNC or O_EXCL if the file is
- * already open. Should we check for it? ie
- * O_EXCL --> error
- * O_TRUNC --> truncate the fork.
- * idem for ressource fork.
- */
- }
- open_df = ADFLAGS_DF;
- ad->ad_data_fork.adf_refcount++;
- }
-
- if (!(adflags & ADFLAGS_HF))
- return 0;
+ int ret = 0;
+ int oflags;
+ int mode;
+
+ LOG(log_debug, logtype_default, "ad_open(\"%s\", %s)",
+ abspath(path), adflags2logstr(adflags));
- /* ****************************************** */
+ if (ad->ad_inited != AD_INITED)
+ AFP_PANIC("ad_open: not initialized");
- if (ad_meta_fileno(ad) != -1) { /* the file is already open */
- if ((oflags & ( O_RDWR | O_WRONLY)) &&
- !(ad->ad_md->adf_flags & ( O_RDWR | O_WRONLY))) {
- if (open_df) {
- /* don't call with ADFLAGS_HF because we didn't open ressource fork */
- ad_close( ad, open_df );
- }
- errno = EACCES;
- return -1;
+ if (ad->ad_fullpath == NULL) {
+ if ((ad->ad_fullpath = bfromcstr(abspath(path))) == NULL) {
+ ret = -1;
+ goto exit;
}
- ad_refresh(ad);
- /* it's not new anymore */
- ad->ad_md->adf_flags &= ~( O_TRUNC | O_CREAT );
- ad->ad_md->adf_refcount++;
- goto sfm;
}
- memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
- ad->ad_rlen = 0;
- ad_p = ad->ad_ops->ad_path( path, adflags );
-
- hoflags = oflags & ~(O_CREAT | O_EXCL);
- if (!(adflags & ADFLAGS_RDONLY)) {
- hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
- }
- ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
- if (ad->ad_md->adf_fd < 0 ) {
- if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
- hoflags = oflags & ~(O_CREAT | O_EXCL);
- ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
+ if ((adflags & ADFLAGS_DF) && !(ad->ad_adflags & ADFLAGS_DF)) {
+ oflags = va_arg(args, int);
+ if (oflags & O_CREAT)
+ mode = va_arg(args, int);
+ if (ad_open_df(path, adflags, oflags, mode, ad) != 0) {
+ ret = -1;
+ goto exit;
}
+ ad->ad_adflags |= ADFLAGS_DF;
}
- if ( ad->ad_md->adf_fd < 0 ) {
- if (errno == ENOENT && (oflags & O_CREAT) ) {
- /*
- * We're expecting to create a new adouble header file,
- * here.
- * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
- */
- LOG(log_debug, logtype_default, "ad_open(\"%s\"): {cwd: \"%s\"} creating adouble file",
- ad_p, getcwdpath());
- admode = mode;
- errno = 0;
- st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
- if ((ad->ad_options & ADVOL_UNIXPRIV)) {
- admode = mode;
- }
- admode = ad_hf_mode(admode);
- if ((errno == ENOENT) && (ad->ad_flags != AD_VERSION2_OSX)) {
- if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
- return ad_error(ad, adflags);
- }
- admode = mode;
- st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
- if ((ad->ad_options & ADVOL_UNIXPRIV)) {
- admode = mode;
- }
- admode = ad_hf_mode(admode);
- }
- /* retry with O_CREAT */
- ad->ad_md->adf_fd = open( ad_p, oflags,admode );
- if ( ad->ad_md->adf_fd < 0 ) {
- return ad_error(ad, adflags);
- }
- ad->ad_md->adf_flags = oflags;
- /* just created, set owner if admin owner (root) */
- if (!st_invalid) {
- ad_chown(ad_p, &st_dir);
- }
- }
- else {
- return ad_error(ad, adflags);
- }
- } else {
- ad->ad_md->adf_flags = hoflags;
- if (fstat(ad->ad_md->adf_fd, &st_meta) == 0 && st_meta.st_size == 0) {
- /* for 0 length files, treat them as new. */
- ad->ad_md->adf_flags |= O_TRUNC;
- }
- else {
- /* we have valid data in st_meta stat structure, reused it
- in ad_header_read
- */
- pst = &st_meta;
+ if ((adflags & ADFLAGS_HF) && !(ad->ad_adflags & ADFLAGS_HF)) {
+ oflags = va_arg(args, int);
+ if (oflags & O_CREAT)
+ mode = va_arg(args, int);
+ if (ad_open_hf(path, adflags, oflags, mode, ad) != 0) {
+ ret = -1;
+ goto exit;
}
+ ad->ad_adflags |= ADFLAGS_HF;
}
- AD_SET(ad->ad_md->adf_off);
-
- ad->ad_md->adf_refcount = 1;
- adf_lock_init(ad->ad_md);
- if ((ad->ad_md->adf_flags & ( O_TRUNC | O_CREAT ))) {
- /*
- * This is a new adouble header file. Initialize the structure,
- * instead of reading it.
- */
- if (new_rfork(path, ad, adflags) < 0) {
- int err = errno;
- /* the file is already deleted, perm, whatever, so return an error*/
- ad_close(ad, adflags);
- errno = err;
- return -1;
- }
- ad_flush(ad);
- } else {
- /* Read the adouble header in and parse it.*/
- if (ad->ad_ops->ad_header_read( ad , pst) < 0
- || ad->ad_ops->ad_header_upgrade(ad, ad_p) < 0)
- {
- int err = errno;
- ad_close( ad, adflags );
- errno = err;
- return -1;
+ if ((adflags & ADFLAGS_RF) && !(ad->ad_adflags & ADFLAGS_RF)) {
+ oflags = va_arg(args, int);
+ if (oflags & O_CREAT)
+ mode = va_arg(args, int);
+ if (ad_open_rf(path, adflags, oflags, mode, ad) != 0) {
+ ret = -1;
+ goto exit;
}
+ ad->ad_adflags |= ADFLAGS_RF;
}
- /* ****************************************** */
- /* open the resource fork if SFM */
-sfm:
- if (ad->ad_flags != AD_VERSION1_SFM) {
- return 0;
- }
-
- if ((adflags & ADFLAGS_DIR)) {
- /* no resource fork for directories / volumes XXX it's false! */
- return 0;
- }
-
- /* untrue yet but ad_close will decremente it*/
- ad->ad_resource_fork.adf_refcount++;
-
- if (ad_reso_fileno(ad) != -1) { /* the file is already open */
- if ((oflags & ( O_RDWR | O_WRONLY)) &&
- !(ad->ad_resource_fork.adf_flags & ( O_RDWR | O_WRONLY))) {
+exit:
+ if (ret != 0) {
+ /* FIXME: ad_close stuff we opened before hitting an error */
+ /* Dont forget ADFLAGS_NOHF !!! */
- ad_close( ad, open_df | ADFLAGS_HF);
- errno = EACCES;
- return -1;
+ if (ad->ad_fullpath) {
+ bdestroy(ad->ad_fullpath);
+ ad->ad_fullpath = NULL;
}
- return 0;
- }
-
- ad_p = ad->ad_ops->ad_path( path, ADFLAGS_RF );
-
- admode = mode;
- st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
-
- if ((ad->ad_options & ADVOL_UNIXPRIV)) {
- admode = mode;
}
- hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
- ad->ad_resource_fork.adf_fd = open( ad_p, hoflags, admode );
-
- if (ad->ad_resource_fork.adf_fd < 0 ) {
- if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
- hoflags = oflags;
- ad->ad_resource_fork.adf_fd =open( ad_p, hoflags, admode );
- }
- }
+ return ret;
+}
- if ( ad->ad_resource_fork.adf_fd < 0) {
- int err = errno;
+int ad_open(struct adouble *ad, const char *path, int adflags, ...)
+{
+ int ret;
+ va_list args;
- ad_close( ad, adflags );
- errno = err;
- return -1;
- }
- adf_lock_init(&ad->ad_resource_fork);
- AD_SET(ad->ad_resource_fork.adf_off);
- ad->ad_resource_fork.adf_flags = hoflags;
- if ((oflags & O_CREAT) && !st_invalid) {
- /* just created, set owner if admin (root) */
- ad_chown(ad_p, &st_dir);
- }
- else if (!fstat(ad->ad_resource_fork.adf_fd, &st_meta)) {
- ad->ad_rlen = st_meta.st_size;
- }
- return 0 ;
+ va_start(args, adflags);
+ ret = vad_open(ad, path, adflags, args);
+ va_end(args);
+ return ret;
}
/*!
*
* @param name name of file/dir
* @param flags ADFLAGS_DIR: name is a directory \n
- * ADFLAGS_CREATE: force creation of header file, but only as user, not as root\n
* ADFLAGS_OPENFORKS: test if name is open by another afpd process
*
* @param adp pointer to struct adouble
- *
- * @note caller MUST pass ADFLAGS_DIR for directories. Whether ADFLAGS_CREATE really creates
- * a adouble file depends on various other volume options, eg. ADVOL_CACHE
*/
int ad_metadata(const char *name, int flags, struct adouble *adp)
{
uid_t uid;
int ret, err, dir;
- int create = O_RDONLY;
dir = flags & ADFLAGS_DIR;
- /* Check if we shall call ad_open with O_CREAT */
- if ( (adp->ad_options & ADVOL_CACHE)
- && ! (adp->ad_options & ADVOL_NOADOUBLE)
- && (flags & ADFLAGS_CREATE) ) {
- create = O_CREAT | O_RDWR;
- }
- if ((ret = ad_open(name, ADFLAGS_HF | dir, create, 0666, adp)) < 0 && errno == EACCES) {
+ if ((ret = ad_open(adp, name, ADFLAGS_HF | dir, O_RDONLY)) < 0 && errno == EACCES) {
uid = geteuid();
if (seteuid(0)) {
LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno));
return -1;
}
/* we are root open read only */
- ret = ad_open(name, ADFLAGS_HF|ADFLAGS_RDONLY| dir, O_RDONLY, 0, adp);
+ ret = ad_open(adp, name, ADFLAGS_HF | dir, O_RDONLY);
err = errno;
if ( seteuid(uid) < 0) {
LOG(log_error, logtype_default, "ad_metadata: can't seteuid back");
}
-/* ----------------------------------- */
-static int new_rfork(const char *path, struct adouble *ad, int adflags)
-{
- const struct entry *eid;
- u_int16_t ashort;
- struct stat st;
-
- ad->ad_magic = AD_MAGIC;
- ad->ad_version = ad->ad_flags & 0x0f0000;
- if (!ad->ad_version) {
- ad->ad_version = AD_VERSION;
- }
-
- memset(ad->ad_filler, 0, sizeof( ad->ad_filler ));
- memset(ad->ad_data, 0, sizeof(ad->ad_data));
-
-#if AD_VERSION == AD_VERSION2
- if (ad->ad_flags == AD_VERSION2)
- eid = entry_order2;
- else if (ad->ad_flags == AD_VERSION2_OSX)
- eid = entry_order_osx;
- else if (ad->ad_flags == AD_VERSION1_SFM) {
- ad->ad_magic = SFM_MAGIC;
- eid = entry_order_sfm;
- }
- else
-#endif
- eid = entry_order1;
-
- while (eid->id) {
- ad->ad_eid[eid->id].ade_off = eid->offset;
- ad->ad_eid[eid->id].ade_len = eid->len;
- eid++;
- }
-
- /* put something sane in the directory finderinfo */
- if ((adflags & ADFLAGS_DIR)) {
- /* set default view */
- ashort = htons(FINDERINFO_CLOSEDVIEW);
- memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRVIEWOFF,
- &ashort, sizeof(ashort));
- } else {
- /* set default creator/type fields */
- memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRTYPEOFF,"\0\0\0\0", 4);
- memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRCREATOFF,"\0\0\0\0", 4);
- }
-
- /* make things invisible */
- if ((ad->ad_options & ADVOL_INVDOTS) && !(adflags & ADFLAGS_CREATE) &&
- (*path == '.') && strcmp(path, ".") && strcmp(path, ".."))
- {
- ashort = htons(ATTRBIT_INVISIBLE);
- ad_setattr(ad, ashort);
- ashort = htons(FINDERINFO_INVISIBLE);
- memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
- }
-
- if (lstat(path, &st) < 0) {
- return -1;
- }
-
- /* put something sane in the date fields */
- ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
- ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
- ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
- ad_setdate(ad, AD_DATE_BACKUP, AD_DATE_START);
- return 0;
-}
-
-/* to do this with mmap, we need the hfs fs to understand how to mmap
- header files. */
int ad_refresh(struct adouble *ad)
{
- if (ad_meta_fileno(ad) < 0)
+ if (ad_meta_fileno(ad) == -1)
return -1;
return ad->ad_ops->ad_header_read(ad, NULL);
}
-int ad_openat(int dirfd, /* dir fd openat like */
+int ad_openat(struct adouble *ad,
+ int dirfd, /* dir fd openat like */
const char *path,
- int adflags,
- int oflags,
- int mode,
- struct adouble *ad)
+ int adflags, ...)
{
int ret = 0;
int cwdfd = -1;
+ va_list args;
if (dirfd != -1) {
if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) {
}
}
- if (ad_open(path, adflags, oflags, mode, ad) < 0) {
+ va_start(args, adflags);
+
+ if (vad_open(ad, path, adflags, args) < 0) {
ret = -1;
goto exit;
}
+ va_end(args);
+
if (dirfd != -1) {
if (fchdir(cwdfd) != 0) {
- LOG(log_error, logtype_afpd, "ad_openat: cant chdir back, exiting");
- exit(EXITERR_SYS);
+ AFP_PANIC("ad_openat: cant chdir back");
}
}
+++ /dev/null
-/*
- * $Id: ad_private.h,v 1.6 2008-12-03 18:35:44 didg Exp $
- */
-
-#ifndef LIBATALK_ADOUBLE_AD_PRIVATE_H
-#define LIBATALK_ADOUBLE_AD_PRIVATE_H 1
-
-#include <atalk/adouble.h>
-
-#ifndef MAP_FAILED
-#define MAP_FAILED ((void *) -1)
-#endif /* ! MAP_FAILED */
-
-/* this is so that we can keep lists of fds referencing the same file
- * around. that way, we can honor locks created by the same process
- * with the same file. */
-
-#define adf_lock_init(a) do { \
- (a)->adf_lockmax = (a)->adf_lockcount = 0; \
- (a)->adf_excl = 0;(a)->adf_lock = NULL; \
-} while (0)
-
-#define adf_lock_free(a) do { \
- int i;\
- if (!(a)->adf_lock) \
- break; \
- for (i = 0; i < (a)->adf_lockcount; i++) {\
- adf_lock_t *lock = (a)->adf_lock + i;\
- if (--(*lock->refcount) < 1)free(lock->refcount); \
- }\
- free((a)->adf_lock); \
- adf_lock_init(a); \
-} while (0)
-
-#endif /* libatalk/adouble/ad_private.h */
/*
- * $Id: ad_read.c,v 1.10 2010-02-10 14:05:37 franklahm Exp $
- *
* Copyright (c) 1990,1991 Regents of The University of Michigan.
* All Rights Reserved.
*
#include "config.h"
#endif /* HAVE_CONFIG_H */
-#include <atalk/adouble.h>
#include <string.h>
#include <sys/param.h>
+#include <errno.h>
+
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
cc = adf_pread(&ad->ad_data_fork, buf, buflen, off);
}
} else {
- off_t r_off;
-
- if ( ad_reso_fileno( ad ) == -1 ) {
- /* resource fork is not open ( cf etc/afp/fork.c) */
- return 0;
- }
- r_off = ad_getentryoff(ad, eid) + off;
-
- if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 ) {
- return( -1 );
- }
- /*
- * We've just read in bytes from the disk that we read earlier
- * into ad_data. If we're going to write this buffer out later,
- * we need to update ad_data.
- * FIXME : always false?
- */
- if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
- if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
- memcpy(buf, ad->ad_data + r_off,
- MIN(sizeof( ad->ad_data ) - r_off, cc));
- } else {
- memcpy(ad->ad_data + r_off, buf,
- MIN(sizeof( ad->ad_data ) - r_off, cc));
+ if (ad->ad_flags != AD_VERSION_EA) {
+ off_t r_off;
+ if ( ad_reso_fileno( ad ) == -1 )
+ /* resource fork is not open ( cf etc/afp/fork.c) */
+ return 0;
+ r_off = ad_getentryoff(ad, eid) + off;
+ if (( cc = adf_pread( &ad->ad_resource_fork, buf, buflen, r_off )) < 0 )
+ return( -1 );
+ /*
+ * We've just read in bytes from the disk that we read earlier
+ * into ad_data. If we're going to write this buffer out later,
+ * we need to update ad_data.
+ * FIXME : always false?
+ */
+ if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
+ if ( ad->ad_resource_fork.adf_flags & O_RDWR ) {
+ memcpy(buf, ad->ad_data + r_off,
+ MIN(sizeof( ad->ad_data ) - r_off, cc));
+ } else {
+ memcpy(ad->ad_data + r_off, buf,
+ MIN(sizeof( ad->ad_data ) - r_off, cc));
+ }
+ }
+ } else { /* AD_VERSION_EA */
+ if ((off + buflen) > ad->ad_rlen) {
+ errno = ERANGE;
+ return -1;
}
+ memcpy(buf, ad->ad_resforkbuf + off, buflen);
+ cc = buflen;
}
}
/*
- * $Id: ad_sendfile.c,v 1.11 2010-01-21 14:14:49 didg Exp $
- *
* Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu)
* All rights reserved. See COPYRIGHT.
*
#endif /* HAVE_CONFIG_H */
#ifdef WITH_SENDFILE
-
-#include <atalk/adouble.h>
-
#include <stdio.h>
-
#include <sys/socket.h>
#include <sys/uio.h>
-
#include <errno.h>
+#include <atalk/adouble.h>
#include <atalk/logger.h>
-#include "ad_private.h"
+
+#include "ad_lock.h"
#if defined(LINUX_BROKEN_SENDFILE_API)
#include "config.h"
#endif /* HAVE_CONFIG_H */
-#include <atalk/adouble.h>
-
+#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <errno.h>
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
+#include <atalk/bstrlib.h>
+#include <atalk/bstradd.h>
#ifndef MIN
#define MIN(a,b) ((a)<(b)?(a):(b))
}
/* end is always 0 */
-ssize_t ad_write(struct adouble *ad, const u_int32_t eid, off_t off, const int end, const char *buf, const size_t buflen)
+ssize_t ad_write(struct adouble *ad, uint32_t eid, off_t off, int end, const char *buf, size_t buflen)
{
struct stat st;
ssize_t cc;
}
if ( eid == ADEID_DFORK ) {
- if ( end ) {
- if ( fstat( ad_data_fileno(ad), &st ) < 0 ) {
- return( -1 );
- }
- off = st.st_size - off;
- }
- cc = adf_pwrite(&ad->ad_data_fork, buf, buflen, off);
- } else if ( eid == ADEID_RFORK ) {
- off_t r_off;
-
- if ( end ) {
- if ( fstat( ad_data_fileno(ad), &st ) < 0 ) {
- return( -1 );
- }
- off = st.st_size - off -ad_getentryoff(ad, eid);
- }
- r_off = ad_getentryoff(ad, eid) + off;
- cc = adf_pwrite(&ad->ad_resource_fork, buf, buflen, r_off);
-
- /* sync up our internal buffer FIXME always false? */
- if (r_off < ad_getentryoff(ad, ADEID_RFORK)) {
- memcpy(ad->ad_data + r_off, buf, MIN(sizeof(ad->ad_data) -r_off, cc));
+ if ( end ) {
+ if ( fstat( ad_data_fileno(ad), &st ) < 0 ) {
+ return( -1 );
+ }
+ off = st.st_size - off;
}
- if ( ad->ad_rlen < off + cc ) {
- ad->ad_rlen = off + cc;
+ cc = adf_pwrite(&ad->ad_data_fork, buf, buflen, off);
+ } else if ( eid == ADEID_RFORK ) {
+ if (ad->ad_flags != AD_VERSION_EA) {
+ off_t r_off;
+ if ( end ) {
+ if ( fstat( ad_data_fileno(ad), &st ) < 0 )
+ return( -1 );
+ off = st.st_size - off -ad_getentryoff(ad, eid);
+ }
+ r_off = ad_getentryoff(ad, eid) + off;
+ cc = adf_pwrite(&ad->ad_resource_fork, buf, buflen, r_off);
+
+ /* sync up our internal buffer FIXME always false? */
+ if (r_off < ad_getentryoff(ad, ADEID_RFORK))
+ memcpy(ad->ad_data + r_off, buf, MIN(sizeof(ad->ad_data) -r_off, cc));
+ if ( ad->ad_rlen < off + cc )
+ ad->ad_rlen = off + cc;
+ } else { /* AD_VERSION_EA */
+ if ((off + buflen) > ad->ad_resforkbufsize) {
+ size_t roundup = (((off + buflen) / RFORK_EA_ALLOCSIZE) + 1) * RFORK_EA_ALLOCSIZE;
+ if ((ad->ad_resforkbuf = realloc(ad->ad_resforkbuf, roundup)) == NULL)
+ return -1;
+ ad->ad_resforkbufsize = roundup;
+ }
+ memcpy(ad->ad_resforkbuf + off, buf, buflen);
+ if ((off + buflen) > ad->ad_rlen)
+ ad->ad_rlen = off + buflen;
+
+ if (sys_lsetxattr(cfrombstr(ad->ad_fullpath), AD_EA_RESO, ad->ad_resforkbuf, ad->ad_rlen, 0) == -1)
+ return -1;
+ cc = buflen;
}
- }
- else {
+ } else {
return -1; /* we don't know how to write if it's not a ressource or data fork */
}
+
return( cc );
}
/* ------------------------ */
int ad_rtruncate( struct adouble *ad, const off_t size)
{
- if ( sys_ftruncate( ad_reso_fileno(ad),
- size + ad->ad_eid[ ADEID_RFORK ].ade_off ) < 0 ) {
- return -1;
- }
+ if (ad->ad_flags != AD_VERSION_EA)
+ if (sys_ftruncate(ad_reso_fileno(ad), size + ad->ad_eid[ ADEID_RFORK ].ade_off ) < 0 )
+ return -1;
+
ad->ad_rlen = size;
return 0;
int ad_dtruncate(struct adouble *ad, const off_t size)
{
- if (sys_ftruncate(ad_data_fileno(ad), size) < 0) {
- return -1;
- }
+ if (sys_ftruncate(ad_data_fileno(ad), size) < 0)
+ return -1;
+
return 0;
}
extern void cnid_cdb_close (struct _cnid_db *);
/* cnid_add.c */
-extern cnid_t cnid_cdb_add (struct _cnid_db *, const struct stat *, const cnid_t,
- char *, const size_t, cnid_t);
+extern cnid_t cnid_cdb_add (struct _cnid_db *, const struct stat *, cnid_t,
+ const char *, size_t, cnid_t);
extern int cnid_cdb_getstamp (struct _cnid_db *, void *, const size_t );
/* cnid_get.c */
-extern cnid_t cnid_cdb_get (struct _cnid_db *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_cdb_get (struct _cnid_db *, cnid_t, const char *, size_t);
extern char *cnid_cdb_resolve (struct _cnid_db *, cnid_t *, void *, size_t );
-extern cnid_t cnid_cdb_lookup (struct _cnid_db *, const struct stat *, const cnid_t,
- char *, const size_t);
+extern cnid_t cnid_cdb_lookup (struct _cnid_db *, const struct stat *, cnid_t,
+ const char *, size_t);
/* cnid_update.c */
-extern int cnid_cdb_update (struct _cnid_db *, const cnid_t, const struct stat *,
- const cnid_t, char *, size_t);
+extern int cnid_cdb_update (struct _cnid_db *, cnid_t, const struct stat *,
+ cnid_t, const char *, size_t);
/* cnid_delete.c */
extern int cnid_cdb_delete (struct _cnid_db *, const cnid_t);
extern int cnid_cdb_unlock (void *);
extern cnid_t cnid_cdb_rebuild_add (struct _cnid_db *, const struct stat *,
- const cnid_t, char *, const size_t, cnid_t);
+ cnid_t, const char *, size_t, cnid_t);
#endif /* include/atalk/cnid_cdb.h */
/*
- * $Id: cnid_cdb_add.c,v 1.8 2009-11-20 17:22:11 didg Exp $
- *
* Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
* All Rights Reserved. See COPYRIGHT.
*
#ifdef CNID_BACKEND_CDB
#include "cnid_cdb_private.h"
-extern int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
- const cnid_t did, char *name, const size_t len);
-
+extern int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+ cnid_t did, const char *name, size_t len);
#define tid NULL
/* ------------------------ */
cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did, char *name, const size_t len,
- cnid_t hint)
+ cnid_t did, const char *name, size_t len, cnid_t hint)
{
CNID_private *db;
DBT key, data;
-/*
- * $Id: cnid_cdb_get.c,v 1.5 2009-10-29 13:38:16 didg Exp $
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include "cnid_cdb_private.h"
/* Return CNID for a given did/name. */
-cnid_t cnid_cdb_get(struct _cnid_db *cdb, const cnid_t did, char *name,
- const size_t len)
+cnid_t cnid_cdb_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
{
char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
CNID_private *db;
-/*
- * $Id: cnid_cdb_lookup.c,v 1.6 2009-11-20 17:22:11 didg Exp $
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
/* This returns the CNID corresponding to a particular file. It will
* also fix up the various databases if there's a problem. */
-cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
- char *name, const size_t len)
+cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+ const char *name, size_t len)
{
unsigned char *buf;
CNID_private *db;
static char *old_dbfiles[] = {"cnid.db", NULL};
-/* -----------------------
- * bandaid for LanTest performance pb. for now not used, cf. ifdef 0 below
-*/
-static int my_yield(void)
-{
- struct timeval t;
- int ret;
-
- t.tv_sec = 0;
- t.tv_usec = 1000;
- ret = select(0, NULL, NULL, NULL, &t);
- return 0;
-}
-
/* --------------- */
static int didname(DB *dbp _U_, const DBT *pkey _U_, const DBT *pdata, DBT *skey)
{
}
}
- db_env_set_func_yield(my_yield);
return cdb;
fail_appinit:
return CNID_INVALID;
}
-/* ------------------------ */
cnid_t cnid_cdb_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did, char *name, const size_t len,
- cnid_t hint)
+ cnid_t did, const char *name, size_t len, cnid_t hint)
{
CNID_private *db;
DBT key, data;
-/*
- * $Id: cnid_cdb_update.c,v 1.4 2009-11-20 17:22:11 didg Exp $
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
/* cnid_update: takes the given cnid and updates the metadata. To
* handle the did/name data, there are a bunch of functions to get
* and set the various fields. */
-int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
- const cnid_t did, char *name, const size_t len
- /*, const char *info, const int infolen*/)
+int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+ cnid_t did, const char *name, size_t len)
{
unsigned char *buf;
CNID_private *db;
vecs = 1;
if (rqst->namelen) {
- iov[1].iov_base = rqst->name;
+ iov[1].iov_base = (char *)rqst->name;
iov[1].iov_len = rqst->namelen;
towrite += rqst->namelen;
vecs++;
/* ---------------------- */
cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did, char *name, const size_t len,
- cnid_t hint)
+ cnid_t did, const char *name, size_t len, cnid_t hint)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
}
/* ---------------------- */
-cnid_t cnid_dbd_get(struct _cnid_db *cdb, const cnid_t did, char *name, const size_t len)
+cnid_t cnid_dbd_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
}
/* ---------------------- */
-cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
- char *name, const size_t len)
+cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
+ const char *name, size_t len)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
}
/* ---------------------- */
-int cnid_dbd_find(struct _cnid_db *cdb, char *name, size_t namelen, void *buffer, size_t buflen)
+int cnid_dbd_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
}
/* ---------------------- */
-int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
- const cnid_t did, char *name, const size_t len)
+int cnid_dbd_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+ cnid_t did, const char *name, size_t len)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
/* ---------------------- */
cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did, char *name, const size_t len,
- cnid_t hint)
+ cnid_t did, const char *name, size_t len, cnid_t hint)
{
CNID_private *db;
struct cnid_dbd_rqst rqst;
extern struct _cnid_module cnid_dbd_module;
extern struct _cnid_db *cnid_dbd_open (struct cnid_open_args *args);
extern void cnid_dbd_close (struct _cnid_db *);
-extern cnid_t cnid_dbd_add (struct _cnid_db *, const struct stat *, const cnid_t,
- char *, const size_t, cnid_t);
-extern cnid_t cnid_dbd_get (struct _cnid_db *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_dbd_add (struct _cnid_db *, const struct stat *, cnid_t,
+ const char *, size_t, cnid_t);
+extern cnid_t cnid_dbd_get (struct _cnid_db *, cnid_t, const char *, size_t);
extern char *cnid_dbd_resolve (struct _cnid_db *, cnid_t *, void *, size_t );
extern int cnid_dbd_getstamp (struct _cnid_db *, void *, const size_t );
-extern cnid_t cnid_dbd_lookup (struct _cnid_db *, const struct stat *, const cnid_t,
- char *, const size_t);
-extern int cnid_dbd_find (struct _cnid_db *cdb, char *name, size_t namelen,
+extern cnid_t cnid_dbd_lookup (struct _cnid_db *, const struct stat *, cnid_t,
+ const char *, size_t);
+extern int cnid_dbd_find (struct _cnid_db *cdb, const char *name, size_t namelen,
void *buffer, size_t buflen);
-extern int cnid_dbd_update (struct _cnid_db *, const cnid_t, const struct stat *,
- const cnid_t, char *, size_t);
+extern int cnid_dbd_update (struct _cnid_db *, cnid_t, const struct stat *,
+ cnid_t, const char *, size_t);
extern int cnid_dbd_delete (struct _cnid_db *, const cnid_t);
extern cnid_t cnid_dbd_rebuild_add(struct _cnid_db *, const struct stat *,
- const cnid_t, char *, const size_t, cnid_t);
+ cnid_t, const char *, size_t, cnid_t);
/* FIXME: These functions could be static in cnid_dbd.c */
/* ------------------------ */
cnid_t cnid_last_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did _U_, char *name _U_, const size_t len _U_, cnid_t hint _U_)
+ cnid_t did _U_, const char *name _U_, size_t len _U_, cnid_t hint _U_)
{
/* FIXME: it relies on fact, that this is never called twice for the same file/dir. */
}
-
/* Return CNID for a given did/name. */
-cnid_t cnid_last_get(struct _cnid_db *cdb _U_, const cnid_t did _U_, char *name _U_, const size_t len _U_)
+cnid_t cnid_last_get(struct _cnid_db *cdb _U_, cnid_t did _U_, const char *name _U_, size_t len _U_)
{
/* FIXME: it relies on fact, that this is never called twice for the same file/dir. */
/* Propably we should look through DID tree. */
}
-
/* */
-cnid_t cnid_last_lookup(struct _cnid_db *cdb _U_, const struct stat *st _U_, const cnid_t did _U_,
- char *name _U_, const size_t len _U_)
+cnid_t cnid_last_lookup(struct _cnid_db *cdb _U_, const struct stat *st _U_, cnid_t did _U_,
+ const char *name _U_, size_t len _U_)
{
/* FIXME: this function doesn't work in [last] scheme ! */
/* Should be never called or CNID should be somewhat refactored again. */
}
-int cnid_last_update(struct _cnid_db *cdb _U_, const cnid_t id _U_, const struct stat *st _U_,
- const cnid_t did _U_, char *name _U_, const size_t len _U_)
+int cnid_last_update(struct _cnid_db *cdb _U_, cnid_t id _U_, const struct stat *st _U_,
+ cnid_t did _U_, const char *name _U_, size_t len _U_)
{
return 0;
}
extern struct _cnid_module cnid_last_module;
extern struct _cnid_db *cnid_last_open (struct cnid_open_args *args);
extern void cnid_last_close (struct _cnid_db *);
-extern cnid_t cnid_last_add (struct _cnid_db *, const struct stat *, const cnid_t,
- char *, const size_t, cnid_t);
-extern cnid_t cnid_last_get (struct _cnid_db *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_last_add (struct _cnid_db *, const struct stat *, cnid_t,
+ const char *, size_t, cnid_t);
+extern cnid_t cnid_last_get (struct _cnid_db *, cnid_t, const char *, size_t);
extern char *cnid_last_resolve (struct _cnid_db *, cnid_t *, void *, size_t);
-extern cnid_t cnid_last_lookup (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t);
-extern int cnid_last_update (struct _cnid_db *, const cnid_t, const struct stat *,
- const cnid_t, char *, size_t);
-extern int cnid_last_delete (struct _cnid_db *, const cnid_t);
+extern cnid_t cnid_last_lookup (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t);
+extern int cnid_last_update (struct _cnid_db *, cnid_t, const struct stat *,
+ cnid_t, const char *, size_t);
+extern int cnid_last_delete (struct _cnid_db *, cnid_t);
#endif /* include/atalk/cnid_last.h */
extern void cnid_tdb_close (struct _cnid_db *);
/* cnid_add.c */
-extern cnid_t cnid_tdb_add (struct _cnid_db *, const struct stat *, const cnid_t,
- char *, const size_t, cnid_t);
+extern cnid_t cnid_tdb_add (struct _cnid_db *, const struct stat *, cnid_t,
+ const char *, size_t, cnid_t);
/* cnid_get.c */
-extern cnid_t cnid_tdb_get (struct _cnid_db *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_tdb_get (struct _cnid_db *, cnid_t, const char *, size_t);
extern char *cnid_tdb_resolve (struct _cnid_db *, cnid_t *, void *, size_t);
-extern cnid_t cnid_tdb_lookup (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t);
+extern cnid_t cnid_tdb_lookup (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t);
/* cnid_update.c */
-extern int cnid_tdb_update (struct _cnid_db *, const cnid_t, const struct stat *,
- const cnid_t, char *, size_t);
+extern int cnid_tdb_update (struct _cnid_db *, cnid_t, const struct stat *,
+ cnid_t, const char *, size_t);
/* cnid_delete.c */
extern int cnid_tdb_delete (struct _cnid_db *, const cnid_t);
/*
- * $Id: cnid_tdb_add.c,v 1.4 2009-11-20 17:37:14 didg Exp $
- *
* Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
* All Rights Reserved. See COPYRIGHT.
*
/* ------------------------ */
cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st,
- const cnid_t did, char *name, const size_t len, cnid_t hint)
+ cnid_t did, const char *name, size_t len, cnid_t hint)
{
const struct stat *lstp;
cnid_t id;
-/*
- * $Id: cnid_tdb_get.c,v 1.4 2009-11-20 17:37:14 didg Exp $
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cnid_tdb.h"
/* Return CNID for a given did/name. */
-cnid_t cnid_tdb_get(struct _cnid_db *cdb, const cnid_t did, char *name, const size_t len)
+cnid_t cnid_tdb_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
{
char start[CNID_DID_LEN + MAXPATHLEN + 1], *buf;
struct _cnid_tdb_private *db;
-/*
- * $Id: cnid_tdb_lookup.c,v 1.6 2009-11-21 11:12:49 didg Exp $
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cnid_tdb.h"
#include <atalk/logger.h>
-cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, char *name, const size_t len)
+cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did, const char *name, size_t len)
{
char *buf;
struct _cnid_tdb_private *db;
/*
- * $Id: cnid_tdb_open.c,v 1.8 2010-03-31 09:47:32 franklahm Exp $
- *
* Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
* All Rights Reserved. See COPYRIGHT.
*
-/*
- * $Id: cnid_tdb_update.c,v 1.6 2009-11-21 11:12:49 didg Exp $
- */
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "cnid_tdb.h"
#include <atalk/logger.h>
-int cnid_tdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
- const cnid_t did, char *name, const size_t len
- /*, const char *info, const int infolen */ )
+int cnid_tdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
+ cnid_t did, const char *name, size_t len)
{
struct _cnid_tdb_private *db;
TDB_DATA key, data, altdata;
noinst_LTLIBRARIES = libcompat.la
libcompat_la_SOURCES = \
- mktemp.c \
getusershell.c \
- strcasecmp.c \
- strstr.c \
- strdup.c \
- inet_aton.c \
rquota_xdr.c \
- pselect.c \
- snprintf.c
+ pselect.c
#if defined(NEED_RQUOTA) || (defined(sun) && defined(__svr4__)) || \
(defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 6)
+#ifndef u_int
+#define u_int unsigned
+#endif
+
#include <rpc/rpc.h>
#include <rpcsvc/rquota.h>
return strerror(errno);
}
+/*!
+ * Make argument path absoulte
+ *
+ * @returns pointer to path or pointer to error messages on error
+ */
+const char *abspath(const char *name)
+{
+ static char buf[MAXPATHLEN + 1];
+ char *p;
+ int n;
+
+ if (name[0] == '/')
+ return name;
+
+ if ((p = getcwd(buf, MAXPATHLEN)) == NULL)
+ return strerror(errno);
+
+ n = strlen(buf);
+ if (buf[n-1] != '/')
+ buf[n++] = '/';
+
+ strlcpy(buf + n, name, MAXPATHLEN - n);
+ return buf;
+}
+
/*!
* Takes a buffer with a path, strips slashs, returns basename
*
strcpy(vol->v_dbpath, value);
break;
case ADOUBLE_VER:
- if (strcasecmp(value, "v1") == 0) {
- vol->v_adouble = AD_VERSION1;
- vol->ad_path = ad_path;
- }
-#if AD_VERSION == AD_VERSION2
- else if (strcasecmp(value, "v2") == 0) {
+ if (strcasecmp(value, "v2") == 0) {
vol->ad_path = ad_path;
vol->v_adouble = AD_VERSION2;
- }
- else if (strcasecmp(value, "osx") == 0) {
- vol->v_adouble = AD_VERSION2_OSX;
- vol->ad_path = ad_path_osx;
- }
-#endif
- else {
+ } else if (strcasecmp(value, "ea") == 0) {
+ vol->ad_path = ad_path_ea;
+ vol->v_adouble = AD_VERSION_EA;
+ } else {
+
fprintf (stderr, "unknown adouble version: %s, %s", buf, value);
return -1;
}
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;
- case AD_VERSION1_SFM:
- strlcat(buf, "ADOUBLE_VER:sfm\n", sizeof(buf));
+ case AD_VERSION_EA:
+ strlcat(buf, "ADOUBLE_VER:ea\n", sizeof(buf));
break;
}
noinst_LTLIBRARIES = libvfs.la
-libvfs_la_SOURCES = vfs.c unix.c ea.c sys_ea.c ea_sys.c
+libvfs_la_SOURCES = vfs.c unix.c ea_ad.c ea_sys.c extattr.c
if HAVE_ACLS
libvfs_la_SOURCES += acl.c
+++ /dev/null
-/*
- Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif /* HAVE_CONFIG_H */
-
-#include <unistd.h>
-#include <stdint.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include <atalk/adouble.h>
-#include <atalk/ea.h>
-#include <atalk/afp.h>
-#include <atalk/logger.h>
-#include <atalk/volume.h>
-#include <atalk/vfs.h>
-#include <atalk/util.h>
-#include <atalk/unix.h>
-
-/*
- * Store Extended Attributes inside .AppleDouble folders as follows:
- *
- * filename "fileWithEAs" with EAs "testEA1" and "testEA2"
- *
- * - create header with with the format struct adouble_ea_ondisk, the file is written to
- * ".AppleDouble/fileWithEAs::EA"
- * - store EAs in files "fileWithEAs::EA::testEA1" and "fileWithEAs::EA::testEA2"
- */
-
-/*
- * Build mode for EA header from file mode
- */
-static inline mode_t ea_header_mode(mode_t mode)
-{
- /* Same as ad_hf_mode(mode) */
- mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
- /* Owner must be able to open, read and w-lock it, in order to chmod from eg 0000 -> 0xxxx*/
- mode |= S_IRUSR | S_IWUSR;
- return mode;
-}
-
-/*
- * Build mode for EA file from file mode
- */
-static inline mode_t ea_mode(mode_t mode)
-{
- /* Same as ad_hf_mode(mode) */
- mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
- return mode;
-}
-
-/*
- Taken form afpd/desktop.c
-*/
-static char *mtoupath(const struct vol *vol, const char *mpath)
-{
- static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
- const char *m;
- char *u;
- size_t inplen;
- size_t outlen;
- uint16_t flags = CONV_ESCAPEHEX | CONV_ALLOW_COLON;
-
- if (!mpath)
- return NULL;
-
- if ( *mpath == '\0' ) {
- return( "." );
- }
-
- m = mpath;
- u = upath;
-
- inplen = strlen(m);
- outlen = MAXPATHLEN;
-
- if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC,
- vol->v_volcharset,
- vol->v_maccharset,
- m, inplen, u, outlen, &flags)) ) {
- return NULL;
- }
-
- return( upath );
-}
-
-
-/*
- * Function: unpack_header
- *
- * Purpose: unpack and verify header file data buffer at ea->ea_data into struct ea
- *
- * Arguments:
- *
- * ea (rw) handle to struct ea
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * Verifies magic and version.
- */
-static int unpack_header(struct ea * restrict ea)
-{
- int ret = 0;
- unsigned int count = 0;
- uint32_t uint32;
- char *buf;
-
- /* Check magic and version */
- buf = ea->ea_data;
- if (*(uint32_t *)buf != htonl(EA_MAGIC)) {
- LOG(log_error, logtype_afpd, "unpack_header: wrong magic 0x%08x", *(uint32_t *)buf);
- ret = -1;
- goto exit;
- }
- buf += 4;
- if (*(uint16_t *)buf != htons(EA_VERSION)) {
- LOG(log_error, logtype_afpd, "unpack_header: wrong version 0x%04x", *(uint16_t *)buf);
- ret = -1;
- goto exit;
- }
- buf += 2;
-
- /* Get EA count */
- ea->ea_count = ntohs(*(uint16_t *)buf);
- LOG(log_debug, logtype_afpd, "unpack_header: number of EAs: %u", ea->ea_count);
- buf += 2;
-
- if (ea->ea_count == 0)
- return 0;
-
- /* Allocate storage for the ea_entries array */
- ea->ea_entries = malloc(sizeof(struct ea_entry) * ea->ea_count);
- if ( ! ea->ea_entries) {
- LOG(log_error, logtype_afpd, "unpack_header: OOM");
- ret = -1;
- goto exit;
- }
-
- buf = ea->ea_data + EA_HEADER_SIZE;
- while (count < ea->ea_count) {
- memcpy(&uint32, buf, 4); /* EA size */
- buf += 4;
- (*(ea->ea_entries))[count].ea_size = ntohl(uint32);
- (*(ea->ea_entries))[count].ea_name = strdup(buf);
- if (! (*(ea->ea_entries))[count].ea_name) {
- LOG(log_error, logtype_afpd, "unpack_header: OOM");
- ret = -1;
- goto exit;
- }
- (*(ea->ea_entries))[count].ea_namelen = strlen((*(ea->ea_entries))[count].ea_name);
- buf += (*(ea->ea_entries))[count].ea_namelen + 1;
-
- LOG(log_maxdebug, logtype_afpd, "unpack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
- (*(ea->ea_entries))[count].ea_name,
- (*(ea->ea_entries))[count].ea_size,
- (*(ea->ea_entries))[count].ea_namelen);
-
- count++;
- }
-
-exit:
- return ret;
-}
-
-/*
- * Function: pack_header
- *
- * Purpose: pack everything from struct ea into buffer at ea->ea_data
- *
- * Arguments:
- *
- * ea (rw) handle to struct ea
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * adjust ea->ea_count in case an ea entry deletetion is detected
- */
-static int pack_header(struct ea * restrict ea)
-{
- unsigned int count = 0, eacount = 0;
- uint16_t uint16;
- uint32_t uint32;
- size_t bufsize = EA_HEADER_SIZE;
-
- char *buf = ea->ea_data + EA_HEADER_SIZE;
-
- LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
- ea->filename, ea->ea_count, ea->ea_size);
-
- if (ea->ea_count == 0)
- /* nothing to do, magic, version and count are still valid in buffer */
- return 0;
-
- while(count < ea->ea_count) { /* the names */
- /* Check if its a deleted entry */
- if ( ! ((*ea->ea_entries)[count].ea_name)) {
- count++;
- continue;
- }
-
- bufsize += (*(ea->ea_entries))[count].ea_namelen + 1;
- count++;
- eacount++;
- }
-
- bufsize += (eacount * 4); /* header + ea_size for each EA */
- if (bufsize > ea->ea_size) {
- /* we must realloc */
- if ( ! (buf = realloc(ea->ea_data, bufsize)) ) {
- LOG(log_error, logtype_afpd, "pack_header: OOM");
- return -1;
- }
- ea->ea_data = buf;
- }
- ea->ea_size = bufsize;
-
- /* copy count */
- uint16 = htons(eacount);
- memcpy(ea->ea_data + EA_COUNT_OFF, &uint16, 2);
-
- count = 0;
- buf = ea->ea_data + EA_HEADER_SIZE;
- while (count < ea->ea_count) {
- /* Check if its a deleted entry */
- if ( ! ((*ea->ea_entries)[count].ea_name)) {
- count++;
- continue;
- }
-
- /* First: EA size */
- uint32 = htonl((*(ea->ea_entries))[count].ea_size);
- memcpy(buf, &uint32, 4);
- buf += 4;
-
- /* Second: EA name as C-string */
- strcpy(buf, (*(ea->ea_entries))[count].ea_name);
- buf += (*(ea->ea_entries))[count].ea_namelen + 1;
-
- LOG(log_maxdebug, logtype_afpd, "pack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
- (*(ea->ea_entries))[count].ea_name,
- (*(ea->ea_entries))[count].ea_size,
- (*(ea->ea_entries))[count].ea_namelen);
-
- count++;
- }
-
- ea->ea_count = eacount;
-
- LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
- ea->filename, ea->ea_count, ea->ea_size);
-
- return 0;
-}
-
-/*
- * Function: ea_addentry
- *
- * Purpose: add one EA into ea->ea_entries[]
- *
- * Arguments:
- *
- * ea (rw) pointer to struct ea
- * attruname (r) name of EA
- * attrsize (r) size of ea
- * bitmap (r) bitmap from FP func
- *
- * Returns: new number of EA entries, -1 on error
- *
- * Effects:
- *
- * Grow array ea->ea_entries[]. If ea->ea_entries is still NULL, start allocating.
- * Otherwise realloc and put entry at the end. Increments ea->ea_count.
- */
-static int ea_addentry(struct ea * restrict ea,
- const char * restrict attruname,
- size_t attrsize,
- int bitmap)
-{
- int ea_existed = 0;
- unsigned int count = 0;
- void *tmprealloc;
-
- /* First check if an EA of the requested name already exist */
- if (ea->ea_count > 0) {
- while (count < ea->ea_count) {
- if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
- ea_existed = 1;
- LOG(log_debug, logtype_afpd, "ea_addentry('%s', bitmap:0x%x): exists", attruname, bitmap);
- if (bitmap & kXAttrCreate)
- /* its like O_CREAT|O_EXCL -> fail */
- return -1;
- (*(ea->ea_entries))[count].ea_size = attrsize;
- return 0;
- }
- count++;
- }
- }
-
- if ((bitmap & kXAttrReplace) && ! ea_existed)
- /* replace was requested, but EA didn't exist */
- return -1;
-
- if (ea->ea_count == 0) {
- ea->ea_entries = malloc(sizeof(struct ea_entry));
- if ( ! ea->ea_entries) {
- LOG(log_error, logtype_afpd, "ea_addentry: OOM");
- return -1;
- }
- } else if (! ea_existed) {
- tmprealloc = realloc(ea->ea_entries, sizeof(struct ea_entry) * (ea->ea_count + 1));
- if ( ! tmprealloc) {
- LOG(log_error, logtype_afpd, "ea_addentry: OOM");
- return -1;
- }
- ea->ea_entries = tmprealloc;
- }
-
- /* We've grown the array, now store the entry */
- (*(ea->ea_entries))[ea->ea_count].ea_size = attrsize;
- (*(ea->ea_entries))[ea->ea_count].ea_name = strdup(attruname);
- if ( ! (*(ea->ea_entries))[ea->ea_count].ea_name) {
- LOG(log_error, logtype_afpd, "ea_addentry: OOM");
- goto error;
- }
- (*(ea->ea_entries))[ea->ea_count].ea_namelen = strlen(attruname);
-
- ea->ea_count++;
- return ea->ea_count;
-
-error:
- if (ea->ea_count == 0 && ea->ea_entries) {
- /* We just allocated storage but had an error somewhere -> free storage*/
- free(ea->ea_entries);
- ea->ea_entries = NULL;
- }
- ea->ea_count = 0;
- return -1;
-}
-
-/*
- * Function: create_ea_header
- *
- * Purpose: create EA header file, only called from ea_open
- *
- * Arguments:
- *
- * uname (r) filename for which we have to create a header
- * ea (rw) ea handle with already allocated storage pointed to
- * by ea->ea_data
- *
- * Returns: fd of open header file on success, -1 on error, errno semantics:
- * EEXIST: open with O_CREAT | O_EXCL failed
- *
- * Effects:
- *
- * Creates EA header file and initialize ea->ea_data buffer.
- * Possibe race condition with other afpd processes:
- * we were called because header file didn't exist in eg. ea_open. We then
- * try to create a file with O_CREAT | O_EXCL, but the whole process in not atomic.
- * What do we do then? Someone else is in the process of creating the header too, but
- * it might not have finished it. That means we cant just open, read and use it!
- * We therefor currently just break with an error.
- * On return the header file is still r/w locked.
- */
-static int create_ea_header(const char * restrict uname,
- struct ea * restrict ea)
-{
- int fd = -1, err = 0;
- char *ptr;
-
- if ((fd = open(uname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
- LOG(log_error, logtype_afpd, "ea_create: open race condition with ea header for file: %s", uname);
- return -1;
- }
-
- /* lock it */
- if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
- LOG(log_error, logtype_afpd, "ea_create: lock race condition with ea header for file: %s", uname);
- err = -1;
- goto exit;
- }
-
- /* Now init it */
- ptr = ea->ea_data;
- *(uint32_t *)ptr = htonl(EA_MAGIC);
- ptr += EA_MAGIC_LEN;
- *(uint16_t *)ptr = htons(EA_VERSION);
- ptr += EA_VERSION_LEN;
- *(uint16_t *)ptr = 0; /* count */
-
- ea->ea_size = EA_HEADER_SIZE;
- ea->ea_inited = EA_INITED;
-
-exit:
- if (err != 0) {
- close(fd);
- fd = -1;
- }
- return fd;
-}
-
-/*
- * Function: write_ea
- *
- * Purpose: write an EA to disk
- *
- * Arguments:
- *
- * ea (r) struct ea handle
- * attruname (r) EA name
- * ibuf (r) buffer with EA content
- * attrsize (r) size of EA
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * Creates/overwrites EA file.
- *
- */
-static int write_ea(const struct ea * restrict ea,
- const char * restrict attruname,
- const char * restrict ibuf,
- size_t attrsize)
-{
- int fd = -1, ret = AFP_OK;
- struct stat st;
- char *eaname;
-
- if ((eaname = ea_path(ea, attruname, 1)) == NULL) {
- LOG(log_error, logtype_afpd, "write_ea('%s'): ea_path error", attruname);
- return AFPERR_MISC;
- }
-
- LOG(log_maxdebug, logtype_afpd, "write_ea('%s')", eaname);
-
- /* Check if it exists, remove if yes*/
- if ((stat(eaname, &st)) == 0) {
- if ((unlink(eaname)) != 0) {
- if (errno == EACCES)
- return AFPERR_ACCESS;
- else
- return AFPERR_MISC;
- }
- }
-
- if ((fd = open(eaname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
- LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
- return -1;
- }
-
- /* lock it */
- if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
- LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
- ret = -1;
- goto exit;
- }
-
- if (write(fd, ibuf, attrsize) != (ssize_t)attrsize) {
- LOG(log_error, logtype_afpd, "write_ea('%s'): write: %s", eaname, strerror(errno));
- ret = -1;
- goto exit;
- }
-
-exit:
- if (fd != -1)
- close(fd); /* and unlock */
- return ret;
-}
-
-/*
- * Function: ea_delentry
- *
- * Purpose: delete one EA from ea->ea_entries[]
- *
- * Arguments:
- *
- * ea (rw) pointer to struct ea
- * attruname (r) EA name
- *
- * Returns: new number of EA entries, -1 on error
- *
- * Effects:
- *
- * Remove entry from ea->ea_entries[]. Decrement ea->ea_count.
- * Marks it as unused just by freeing name and setting it to NULL.
- * ea_close and pack_buffer must honor this.
- */
-static int ea_delentry(struct ea * restrict ea, const char * restrict attruname)
-{
- int ret = 0;
- unsigned int count = 0;
-
- if (ea->ea_count == 0) {
- LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion");
- return -1;
- }
-
- while (count < ea->ea_count) {
- /* search matching EA */
- if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
- free((*ea->ea_entries)[count].ea_name);
- (*ea->ea_entries)[count].ea_name = NULL;
-
- LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u",
- attruname, count + 1, ea->ea_count);
-
- break;
- }
- count++;
- }
-
- return ret;
-}
-
-/*
- * Function: delete_ea_file
- *
- * Purpose: delete EA file from disk
- *
- * Arguments:
- *
- * ea (r) struct ea handle
- * attruname (r) EA name
- *
- * Returns: 0 on success, -1 on error
- */
-static int delete_ea_file(const struct ea * restrict ea, const char *eaname)
-{
- int ret = 0;
- char *eafile;
- struct stat st;
-
- if ((eafile = ea_path(ea, eaname, 1)) == NULL) {
- LOG(log_error, logtype_afpd, "delete_ea_file('%s'): ea_path error", eaname);
- return -1;
- }
-
- /* Check if it exists, remove if yes*/
- if ((stat(eafile, &st)) == 0) {
- if ((unlink(eafile)) != 0) {
- LOG(log_error, logtype_afpd, "delete_ea_file('%s'): unlink: %s",
- eafile, strerror(errno));
- ret = -1;
- } else
- LOG(log_debug, logtype_afpd, "delete_ea_file('%s'): success", eafile);
- }
-
- return ret;
-}
-
-/*************************************************************************************
- * ea_path, ea_open and ea_close are only global so that dbd can call them
- *************************************************************************************/
-
-/*
- * Function: ea_path
- *
- * Purpose: return name of ea header filename
- *
- * Arguments:
- *
- * ea (r) ea handle
- * eaname (r) name of EA or NULL
- * macname (r) if != 0 call mtoupath on eaname
- *
- * Returns: pointer to name in static buffer, NULL on error
- *
- * Effects:
- *
- * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme
- * Files: "file" -> "file/.AppleDouble/file::EA"
- * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA"
- * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA"
- */
-char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname)
-{
- char *adname;
- static char pathbuf[MAXPATHLEN + 1];
-
- /* get name of a adouble file from uname */
- adname = ea->vol->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0);
- /* copy it so we can work with it */
- strlcpy(pathbuf, adname, MAXPATHLEN + 1);
- /* append "::EA" */
- strlcat(pathbuf, "::EA", MAXPATHLEN + 1);
-
- if (eaname) {
- strlcat(pathbuf, "::", MAXPATHLEN + 1);
- if (macname)
- if ((eaname = mtoupath(ea->vol, eaname)) == NULL)
- return NULL;
- strlcat(pathbuf, eaname, MAXPATHLEN + 1);
- }
-
- return pathbuf;
-}
-
-/*
- * Function: ea_open
- *
- * Purpose: open EA header file, create if it doesnt exits and called with O_CREATE
- *
- * Arguments:
- *
- * vol (r) current volume
- * uname (r) filename for which we have to open a header
- * flags (r) EA_CREATE: create if it doesn't exist (without it won't be created)
- * EA_RDONLY: open read only
- * EA_RDWR: open read/write
- * Eiterh EA_RDONLY or EA_RDWR MUST be requested
- * ea (w) pointer to a struct ea that we fill
- *
- * Returns: 0 on success
- * -1 on misc error with errno = EFAULT
- * -2 if no EA header exists with errno = ENOENT
- *
- * Effects:
- *
- * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
- * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
- * file is either read or write locked depending on the open flags.
- * When you're done with struct ea you must call ea_close on it.
- */
-int ea_open(const struct vol * restrict vol,
- const char * restrict uname,
- eaflags_t eaflags,
- struct ea * restrict ea)
-{
- int ret = 0;
- char *eaname;
- struct stat st;
-
- /* Enforce usage rules! */
- if ( ! (eaflags & (EA_RDONLY | EA_RDWR))) {
- LOG(log_error, logtype_afpd, "ea_open: called without EA_RDONLY | EA_RDWR", uname);
- return -1;
- }
-
- /* Set it all to 0 */
- memset(ea, 0, sizeof(struct ea));
-
- ea->vol = vol; /* ea_close needs it */
- ea->ea_flags = eaflags;
- ea->dirfd = -1; /* no *at (cf openat) semantics by default */
-
- /* Dont care for errors, eg when removing the file is already gone */
- if (!stat(uname, &st) && S_ISDIR(st.st_mode))
- ea->ea_flags |= EA_DIR;
-
- if ( ! (ea->filename = strdup(uname))) {
- LOG(log_error, logtype_afpd, "ea_open: OOM");
- return -1;
- }
-
- eaname = ea_path(ea, NULL, 0);
- LOG(log_maxdebug, logtype_afpd, "ea_open: ea_path: %s", eaname);
-
- /* Check if it exists, if not create it if EA_CREATE is in eaflags */
- if ((stat(eaname, &st)) != 0) {
- if (errno == ENOENT) {
-
- /* It doesnt exist */
-
- if ( ! (eaflags & EA_CREATE)) {
- /* creation was not requested, so return with error */
- ret = -2;
- goto exit;
- }
-
- /* Now create a header file */
-
- /* malloc buffer for minimal on disk data */
- ea->ea_data = malloc(EA_HEADER_SIZE);
- if (! ea->ea_data) {
- LOG(log_error, logtype_afpd, "ea_open: OOM");
- ret = -1;
- goto exit;
- }
-
- /* create it */
- ea->ea_fd = create_ea_header(eaname, ea);
- if (ea->ea_fd == -1) {
- ret = -1;
- goto exit;
- }
-
- return 0;
-
- } else {/* errno != ENOENT */
- ret = -1;
- goto exit;
- }
- }
-
- /* header file exists, so read and parse it */
-
- /* malloc buffer where we read disk file into */
- if (st.st_size < EA_HEADER_SIZE) {
- LOG(log_error, logtype_afpd, "ea_open('%s'): bogus EA header file", eaname);
- ret = -1;
- goto exit;
- }
- ea->ea_size = st.st_size;
- ea->ea_data = malloc(st.st_size);
- if (! ea->ea_data) {
- LOG(log_error, logtype_afpd, "ea_open: OOM");
- ret = -1;
- goto exit;
- }
-
- /* Now lock, open and read header file from disk */
- if ((ea->ea_fd = open(eaname, (ea->ea_flags & EA_RDWR) ? O_RDWR : O_RDONLY)) == -1) {
- LOG(log_error, logtype_afpd, "ea_open('%s'): error: %s", eaname, strerror(errno));
- ret = -1;
- goto exit;
- }
-
- /* lock it */
- if (ea->ea_flags & EA_RDONLY) {
- /* read lock */
- if ((read_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
- LOG(log_error, logtype_afpd, "ea_open: lock error on header: %s", eaname);
- ret = -1;
- goto exit;
- }
- } else { /* EA_RDWR */
- /* write lock */
- if ((write_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
- LOG(log_error, logtype_afpd, "ea_open: lock error on header: %s", eaname);
- ret = -1;
- goto exit;
- }
- }
-
- /* read it */
- if (read(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
- LOG(log_error, logtype_afpd, "ea_open: short read on header: %s", eaname);
- ret = -1;
- goto exit;
- }
-
- if ((unpack_header(ea)) != 0) {
- LOG(log_error, logtype_afpd, "ea_open: error unpacking header for: %s", eaname);
- ret = -1;
- goto exit;
- }
-
-exit:
- switch (ret) {
- case 0:
- ea->ea_inited = EA_INITED;
- break;
- case -1:
- errno = EFAULT; /* force some errno distinguishable from ENOENT */
- /* fall through */
- case -2:
- if (ea->ea_data) {
- free(ea->ea_data);
- ea->ea_data = NULL;
- }
- if (ea->ea_fd) {
- close(ea->ea_fd);
- ea->ea_fd = -1;
- }
- break;
- }
-
- return ret;
-}
-
-/*
- * Function: ea_openat
- *
- * Purpose: openat like wrapper for ea_open, takes a additional file descriptor
- *
- * Arguments:
- *
- * vol (r) current volume
- * sfd (r) openat like file descriptor
- * uname (r) filename for which we have to open a header
- * flags (r) EA_CREATE: create if it doesn't exist (without it won't be created)
- * EA_RDONLY: open read only
- * EA_RDWR: open read/write
- * Eiterh EA_RDONLY or EA_RDWR MUST be requested
- * ea (w) pointer to a struct ea that we fill
- *
- * Returns: 0 on success
- * -1 on misc error with errno = EFAULT
- * -2 if no EA header exists with errno = ENOENT
- *
- * Effects:
- *
- * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
- * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
- * file is either read or write locked depending on the open flags.
- * When you're done with struct ea you must call ea_close on it.
- */
-int ea_openat(const struct vol * restrict vol,
- int dirfd,
- const char * restrict uname,
- eaflags_t eaflags,
- struct ea * restrict ea)
-{
- int ret = 0;
- int cwdfd = -1;
-
- if (dirfd != -1) {
- if (((cwdfd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
- ret = -1;
- goto exit;
- }
- }
-
- ret = ea_open(vol, uname, eaflags, ea);
- ea->dirfd = dirfd;
-
- if (dirfd != -1) {
- if (fchdir(cwdfd) != 0) {
- LOG(log_error, logtype_afpd, "ea_openat: cant chdir back, exiting");
- exit(EXITERR_SYS);
- }
- }
-
-
-exit:
- if (cwdfd != -1)
- close(cwdfd);
-
- return ret;
-
-}
-
-/*
- * Function: ea_close
- *
- * Purpose: flushes and closes an ea handle
- *
- * Arguments:
- *
- * ea (rw) pointer to ea handle
- *
- * Returns: 0 on success, -1 on error
- *
- * Effects:
- *
- * Flushes and then closes and frees all resouces held by ea handle.
- * Pack data in ea into ea_data, then write ea_data to disk
- */
-int ea_close(struct ea * restrict ea)
-{
- int ret = 0;
- unsigned int count = 0;
- char *eaname;
- struct stat st;
-
- LOG(log_debug, logtype_afpd, "ea_close('%s')", ea->filename);
-
- if (ea->ea_inited != EA_INITED) {
- LOG(log_warning, logtype_afpd, "ea_close('%s'): non initialized ea", ea->filename);
- return 0;
- }
-
- /* pack header and write it to disk if it was opened EA_RDWR*/
- if (ea->ea_flags & EA_RDWR) {
- if ((pack_header(ea)) != 0) {
- LOG(log_error, logtype_afpd, "ea_close: pack header");
- ret = -1;
- } else {
- if (ea->ea_count == 0) {
- /* Check if EA header exists and remove it */
- eaname = ea_path(ea, NULL, 0);
- if ((lstatat(ea->dirfd, eaname, &st)) == 0) {
- if ((netatalk_unlinkat(ea->dirfd, eaname)) != 0) {
- LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s",
- eaname, strerror(errno));
- ret = -1;
- }
- else
- LOG(log_debug, logtype_afpd, "ea_close(unlink '%s'): success", eaname);
- } else {
- /* stat error */
- if (errno != ENOENT) {
- LOG(log_error, logtype_afpd, "ea_close('%s'): stat: %s",
- eaname, strerror(errno));
- ret = -1;
- }
- }
- } else { /* ea->ea_count > 0 */
- if ((lseek(ea->ea_fd, 0, SEEK_SET)) == -1) {
- LOG(log_error, logtype_afpd, "ea_close: lseek: %s", strerror(errno));
- ret = -1;
- goto exit;
- }
-
- if ((ftruncate(ea->ea_fd, 0)) == -1) {
- LOG(log_error, logtype_afpd, "ea_close: ftruncate: %s", strerror(errno));
- ret = -1;
- goto exit;
- }
-
- if (write(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
- LOG(log_error, logtype_afpd, "ea_close: write: %s", strerror(errno));
- ret = -1;
- }
- }
- }
- }
-
-exit:
- /* free names */
- while(count < ea->ea_count) {
- if ( (*ea->ea_entries)[count].ea_name ) {
- free((*ea->ea_entries)[count].ea_name);
- (*ea->ea_entries)[count].ea_name = NULL;
- }
- count++;
- }
- ea->ea_count = 0;
-
- if (ea->filename) {
- free(ea->filename);
- ea->filename = NULL;
- }
-
- if (ea->ea_entries) {
- free(ea->ea_entries);
- ea->ea_entries = NULL;
- }
-
- if (ea->ea_data) {
- free(ea->ea_data);
- ea->ea_data = NULL;
- }
- if (ea->ea_fd != -1) {
- close(ea->ea_fd); /* also releases the fcntl lock */
- ea->ea_fd = -1;
- }
-
- return 0;
-}
-
-
-
-/************************************************************************************
- * VFS funcs called from afp_ea* funcs
- ************************************************************************************/
-
-/*
- * Function: get_easize
- *
- * Purpose: get size of an EA
- *
- * Arguments:
- *
- * vol (r) current volume
- * rbuf (w) DSI reply buffer
- * rbuflen (rw) current length of data in reply buffer
- * uname (r) filename
- * oflag (r) link and create flag
- * attruname (r) name of attribute
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies EA size into rbuf in network order. Increments *rbuflen +4.
- */
-int get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
-{
- int ret = AFPERR_MISC;
- unsigned int count = 0;
- uint32_t uint32;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "get_easize: file: %s", uname);
-
- if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
- if (errno != ENOENT)
- LOG(log_error, logtype_afpd, "get_easize: error calling ea_open for file: %s", uname);
-
- memset(rbuf, 0, 4);
- *rbuflen += 4;
- return ret;
- }
-
- while (count < ea.ea_count) {
- if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
- uint32 = htonl((*ea.ea_entries)[count].ea_size);
- memcpy(rbuf, &uint32, 4);
- *rbuflen += 4;
- ret = AFP_OK;
-
- LOG(log_debug, logtype_afpd, "get_easize(\"%s\"): size: %u",
- attruname, (*ea.ea_entries)[count].ea_size);
- break;
- }
- count++;
- }
-
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "get_easize: error closing ea handle for file: %s", uname);
- return AFPERR_MISC;
- }
-
- return ret;
-}
-
-/*
- * Function: get_eacontent
- *
- * Purpose: copy EA into rbuf
- *
- * Arguments:
- *
- * vol (r) current volume
- * rbuf (w) DSI reply buffer
- * rbuflen (rw) current length of data in reply buffer
- * uname (r) filename
- * oflag (r) link and create flag
- * attruname (r) name of attribute
- * maxreply (r) maximum EA size as of current specs/real-life
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies EA into rbuf. Increments *rbuflen accordingly.
- */
-int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
-{
- int ret = AFPERR_MISC, fd = -1;
- unsigned int count = 0;
- uint32_t uint32;
- size_t toread;
- struct ea ea;
- char *eafile;
-
- LOG(log_debug, logtype_afpd, "get_eacontent('%s/%s')", uname, attruname);
-
- if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
- if (errno != ENOENT)
- LOG(log_error, logtype_afpd, "get_eacontent('%s'): ea_open error", uname);
- memset(rbuf, 0, 4);
- *rbuflen += 4;
- return ret;
- }
-
- while (count < ea.ea_count) {
- if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
- if ( (eafile = ea_path(&ea, attruname, 1)) == NULL) {
- ret = AFPERR_MISC;
- break;
- }
-
- if ((fd = open(eafile, O_RDONLY)) == -1) {
- LOG(log_error, logtype_afpd, "get_eacontent('%s'): open error: %s", uname, strerror(errno));
- ret = AFPERR_MISC;
- break;
- }
-
- /* Check how much the client wants, give him what we think is right */
- maxreply -= MAX_REPLY_EXTRA_BYTES;
- if (maxreply > MAX_EA_SIZE)
- maxreply = MAX_EA_SIZE;
- toread = (maxreply < (*ea.ea_entries)[count].ea_size) ? maxreply : (*ea.ea_entries)[count].ea_size;
- LOG(log_debug, logtype_afpd, "get_eacontent('%s'): sending %u bytes", attruname, toread);
-
- /* Put length of EA data in reply buffer */
- uint32 = htonl(toread);
- memcpy(rbuf, &uint32, 4);
- rbuf += 4;
- *rbuflen += 4;
-
- if (read(fd, rbuf, toread) != (ssize_t)toread) {
- LOG(log_error, logtype_afpd, "get_eacontent('%s/%s'): short read", uname, attruname);
- close(fd);
- ret = AFPERR_MISC;
- break;
- }
- *rbuflen += toread;
- close(fd);
-
- ret = AFP_OK;
- break;
- }
- count++;
- }
-
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "get_eacontent('%s'): error closing ea handle", uname);
- return AFPERR_MISC;
- }
-
- return ret;
-
-}
-
-/*
- * Function: list_eas
- *
- * Purpose: copy names of EAs into attrnamebuf
- *
- * Arguments:
- *
- * vol (r) current volume
- * attrnamebuf (w) store names a consecutive C strings here
- * buflen (rw) length of names in attrnamebuf
- * uname (r) filename
- * oflag (r) link and create flag
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies names of all EAs of uname as consecutive C strings into rbuf.
- * Increments *buflen accordingly.
- */
-int list_eas(VFS_FUNC_ARGS_EA_LIST)
-{
- unsigned int count = 0;
- int attrbuflen = *buflen, ret = AFP_OK, len;
- char *buf = attrnamebuf;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "list_eas: file: %s", uname);
-
- if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
- if (errno != ENOENT) {
- LOG(log_error, logtype_afpd, "list_eas: error calling ea_open for file: %s", uname);
- return AFPERR_MISC;
- }
- else
- return AFP_OK;
- }
-
- while (count < ea.ea_count) {
- /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
- if ( ( len = convert_string(vol->v_volcharset,
- CH_UTF8_MAC,
- (*ea.ea_entries)[count].ea_name,
- (*ea.ea_entries)[count].ea_namelen,
- buf + attrbuflen,
- 255))
- <= 0 ) {
- ret = AFPERR_MISC;
- goto exit;
- }
- if (len == 255)
- /* convert_string didn't 0-terminate */
- attrnamebuf[attrbuflen + 255] = 0;
-
- LOG(log_debug7, logtype_afpd, "list_eas(%s): EA: %s",
- uname, (*ea.ea_entries)[count].ea_name);
-
- attrbuflen += len + 1;
- if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
- /* Next EA name could overflow, so bail out with error.
- FIXME: evantually malloc/memcpy/realloc whatever.
- Is it worth it ? */
- LOG(log_warning, logtype_afpd, "list_eas(%s): running out of buffer for EA names", uname);
- ret = AFPERR_MISC;
- goto exit;
- }
- count++;
- }
-
-exit:
- *buflen = attrbuflen;
-
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "list_eas: error closing ea handle for file: %s", uname);
- return AFPERR_MISC;
- }
-
- return ret;
-}
-
-/*
- * Function: set_ea
- *
- * Purpose: set a Solaris native EA
- *
- * Arguments:
- *
- * vol (r) current volume
- * uname (r) filename
- * attruname (r) EA name
- * ibuf (r) buffer with EA content
- * attrsize (r) length EA in ibuf
- * oflag (r) link and create flag
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Copies names of all EAs of uname as consecutive C strings into rbuf.
- * Increments *rbuflen accordingly.
- */
-int set_ea(VFS_FUNC_ARGS_EA_SET)
-{
- int ret = AFP_OK;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "set_ea: file: %s", uname);
-
- if ((ea_open(vol, uname, EA_CREATE | EA_RDWR, &ea)) != 0) {
- LOG(log_error, logtype_afpd, "set_ea('%s'): ea_open error", uname);
- return AFPERR_MISC;
- }
-
- if ((ea_addentry(&ea, attruname, attrsize, oflag)) == -1) {
- LOG(log_error, logtype_afpd, "set_ea('%s'): ea_addentry error", uname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- if ((write_ea(&ea, attruname, ibuf, attrsize)) != 0) {
- LOG(log_error, logtype_afpd, "set_ea('%s'): write_ea error", uname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
-exit:
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "set_ea('%s'): ea_close error", uname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- return ret;
-}
-
-/*
- * Function: remove_ea
- *
- * Purpose: remove a EA from a file
- *
- * Arguments:
- *
- * vol (r) current volume
- * uname (r) filename
- * attruname (r) EA name
- * oflag (r) link and create flag
- *
- * Returns: AFP code: AFP_OK on success or appropiate AFP error code
- *
- * Effects:
- *
- * Removes EA attruname from file uname.
- */
-int remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
-{
- int ret = AFP_OK;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "remove_ea('%s/%s')", uname, attruname);
-
- if ((ea_open(vol, uname, EA_RDWR, &ea)) != 0) {
- LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_open error", uname);
- return AFPERR_MISC;
- }
-
- if ((ea_delentry(&ea, attruname)) == -1) {
- LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_delentry error", uname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- if ((delete_ea_file(&ea, attruname)) != 0) {
- LOG(log_error, logtype_afpd, "remove_ea('%s'): delete_ea error", uname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
-exit:
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_close error", uname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- return ret;
-}
-
-/******************************************************************************************
- * EA VFS funcs that deal with file/dir cp/mv/rm
- ******************************************************************************************/
-
-int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
-{
- unsigned int count = 0;
- int ret = AFP_OK;
- int cwd = -1;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file);
-
- /* Open EA stuff */
- if ((ea_openat(vol, dirfd, file, EA_RDWR, &ea)) != 0) {
- if (errno == ENOENT)
- /* no EA files, nothing to do */
- return AFP_OK;
- else {
- LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error calling ea_open", file);
- return AFPERR_MISC;
- }
- }
-
- if (dirfd != -1) {
- if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
- ret = AFPERR_MISC;
- goto exit;
- }
- }
-
- while (count < ea.ea_count) {
- if ((delete_ea_file(&ea, (*ea.ea_entries)[count].ea_name)) != 0) {
- ret = AFPERR_MISC;
- continue;
- }
- free((*ea.ea_entries)[count].ea_name);
- (*ea.ea_entries)[count].ea_name = NULL;
- count++;
- }
-
- /* ea_close removes the EA header file for us because all names are NULL */
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error closing ea handle", file);
- ret = AFPERR_MISC;
- }
-
- if (dirfd != -1 && fchdir(cwd) != 0) {
- LOG(log_error, logtype_afpd, "ea_deletefile: cant chdir back. exit!");
- exit(EXITERR_SYS);
- }
-
-exit:
- if (cwd != -1)
- close(cwd);
-
- return ret;
-}
-
-int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE)
-{
- unsigned int count = 0;
- int ret = AFP_OK;
- size_t easize;
- char srceapath[ MAXPATHLEN + 1];
- char *eapath;
- char *eaname;
- struct ea srcea;
- struct ea dstea;
- struct adouble ad;
-
- LOG(log_debug, logtype_afpd, "ea_renamefile('%s'/'%s')", src, dst);
-
-
- /* Open EA stuff */
- if ((ea_openat(vol, dirfd, src, EA_RDWR, &srcea)) != 0) {
- if (errno == ENOENT)
- /* no EA files, nothing to do */
- return AFP_OK;
- else {
- LOG(log_error, logtype_afpd, "ea_renamefile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
- return AFPERR_MISC;
- }
- }
-
- if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
- if (errno == ENOENT) {
- /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ((ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) != 0) {
- LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): ad_open error: '%s'", src, dst, dst);
- ret = AFPERR_MISC;
- goto exit;
- }
- ad_close(&ad, ADFLAGS_HF);
- if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
- ret = AFPERR_MISC;
- goto exit;
- }
- }
- }
-
- /* Loop through all EAs: */
- while (count < srcea.ea_count) {
- /* Move EA */
- eaname = (*srcea.ea_entries)[count].ea_name;
- easize = (*srcea.ea_entries)[count].ea_size;
-
- /* Build src and dst paths for rename() */
- if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
- ret = AFPERR_MISC;
- goto exit;
- }
- strcpy(srceapath, eapath);
- if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
- ret = AFPERR_MISC;
- goto exit;
- }
-
- LOG(log_maxdebug, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
- src, dst, srceapath, eapath);
-
- /* Add EA to dstea */
- if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
- LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
- src, dst, srceapath, eapath);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- /* Remove EA entry from srcea */
- if ((ea_delentry(&srcea, eaname)) == -1) {
- LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
- src, dst, srceapath, eapath);
- ea_delentry(&dstea, eaname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- /* Now rename the EA */
- if ((unix_rename(dirfd, srceapath, -1, eapath)) < 0) {
- LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
- src, dst, srceapath, eapath);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- count++;
- }
-
-
-exit:
- ea_close(&srcea);
- ea_close(&dstea);
- return ret;
-}
-
-int ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
-{
- unsigned int count = 0;
- int ret = AFP_OK;
- size_t easize;
- char srceapath[ MAXPATHLEN + 1];
- char *eapath;
- char *eaname;
- struct ea srcea;
- struct ea dstea;
- struct adouble ad;
-
- LOG(log_debug, logtype_afpd, "ea_copyfile('%s'/'%s')", src, dst);
-
- /* Open EA stuff */
- if ((ea_openat(vol, sfd, src, EA_RDWR, &srcea)) != 0) {
- if (errno == ENOENT)
- /* no EA files, nothing to do */
- return AFP_OK;
- else {
- LOG(log_error, logtype_afpd, "ea_copyfile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
- return AFPERR_MISC;
- }
- }
-
- if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
- if (errno == ENOENT) {
- /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if ((ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) != 0) {
- LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ad_open error: '%s'", src, dst, dst);
- ret = AFPERR_MISC;
- goto exit;
- }
- ad_close(&ad, ADFLAGS_HF);
- if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
- ret = AFPERR_MISC;
- goto exit;
- }
- }
- }
-
- /* Loop through all EAs: */
- while (count < srcea.ea_count) {
- /* Copy EA */
- eaname = (*srcea.ea_entries)[count].ea_name;
- easize = (*srcea.ea_entries)[count].ea_size;
-
- /* Build src and dst paths for copy_file() */
- if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
- ret = AFPERR_MISC;
- goto exit;
- }
- strcpy(srceapath, eapath);
- if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
- ret = AFPERR_MISC;
- goto exit;
- }
-
- LOG(log_maxdebug, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
- src, dst, srceapath, eapath);
-
- /* Add EA to dstea */
- if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
- LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ea_addentry('%s') error",
- src, dst, eaname);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- /* Now copy the EA */
- if ((copy_file(sfd, srceapath, eapath, (0666 & ~vol->v_umask))) < 0) {
- LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
- src, dst, srceapath, eapath);
- ret = AFPERR_MISC;
- goto exit;
- }
-
- count++;
- }
-
-exit:
- ea_close(&srcea);
- ea_close(&dstea);
- return ret;
-}
-
-int ea_chown(VFS_FUNC_ARGS_CHOWN)
-{
-
- unsigned int count = 0;
- int ret = AFP_OK;
- char *eaname;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "ea_chown('%s')", path);
- /* Open EA stuff */
- if ((ea_open(vol, path, EA_RDWR, &ea)) != 0) {
- if (errno == ENOENT)
- /* no EA files, nothing to do */
- return AFP_OK;
- else {
- LOG(log_error, logtype_afpd, "ea_chown('%s'): error calling ea_open", path);
- return AFPERR_MISC;
- }
- }
-
- if ((lchown(ea_path(&ea, NULL, 0), uid, gid)) != 0) {
- switch (errno) {
- case EPERM:
- case EACCES:
- ret = AFPERR_ACCESS;
- goto exit;
- default:
- ret = AFPERR_MISC;
- goto exit;
- }
- }
-
- while (count < ea.ea_count) {
- if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
- ret = AFPERR_MISC;
- goto exit;
- }
- if ((lchown(eaname, uid, gid)) != 0) {
- switch (errno) {
- case EPERM:
- case EACCES:
- ret = AFPERR_ACCESS;
- goto exit;
- default:
- ret = AFPERR_MISC;
- goto exit;
- }
- continue;
- }
-
- count++;
- }
-
-exit:
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "ea_chown('%s'): error closing ea handle", path);
- return AFPERR_MISC;
- }
-
- return ret;
-}
-
-int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE)
-{
-
- unsigned int count = 0;
- int ret = AFP_OK;
- const char *eaname;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "ea_chmod_file('%s')", name);
- /* Open EA stuff */
- if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
- if (errno == ENOENT)
- /* no EA files, nothing to do */
- return AFP_OK;
- else
- return AFPERR_MISC;
- }
-
- /* Set mode on EA header file */
- if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
- LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
- switch (errno) {
- case EPERM:
- case EACCES:
- ret = AFPERR_ACCESS;
- goto exit;
- default:
- ret = AFPERR_MISC;
- goto exit;
- }
- }
-
- /* Set mode on EA files */
- while (count < ea.ea_count) {
- if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
- ret = AFPERR_MISC;
- goto exit;
- }
- if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
- LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", eaname, strerror(errno));
- switch (errno) {
- case EPERM:
- case EACCES:
- ret = AFPERR_ACCESS;
- goto exit;
- default:
- ret = AFPERR_MISC;
- goto exit;
- }
- continue;
- }
-
- count++;
- }
-
-exit:
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): error closing ea handle", name);
- return AFPERR_MISC;
- }
-
- return ret;
-}
-
-int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE)
-{
-
- int ret = AFP_OK;
- unsigned int count = 0;
- uid_t uid;
- const char *eaname;
- const char *eaname_safe = NULL;
- struct ea ea;
-
- LOG(log_debug, logtype_afpd, "ea_chmod_dir('%s')", name);
- /* .AppleDouble already might be inaccesible, so we must run as id 0 */
- uid = geteuid();
- if (seteuid(0)) {
- LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): seteuid: %s", name, strerror(errno));
- return AFPERR_MISC;
- }
-
- /* Open EA stuff */
- if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
- /* ENOENT --> no EA files, nothing to do */
- if (errno != ENOENT)
- ret = AFPERR_MISC;
- if (seteuid(uid) < 0) {
- LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
- exit(EXITERR_SYS);
- }
- return ret;
- }
-
- /* Set mode on EA header */
- if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
- LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
- switch (errno) {
- case EPERM:
- case EACCES:
- ret = AFPERR_ACCESS;
- goto exit;
- default:
- ret = AFPERR_MISC;
- goto exit;
- }
- }
-
- /* Set mode on EA files */
- while (count < ea.ea_count) {
- eaname = (*ea.ea_entries)[count].ea_name;
- /*
- * Be careful with EA names from the EA header!
- * Eg NFS users might have access to them, can inject paths using ../ or /.....
- * FIXME:
- * Until the EA code escapes / in EA name requests from the client, these therefor wont work.
- */
- if ((eaname_safe = strrchr(eaname, '/'))) {
- LOG(log_warning, logtype_afpd, "ea_chmod_dir('%s'): contains a slash", eaname);
- eaname = eaname_safe;
- }
- if ((eaname = ea_path(&ea, eaname, 1)) == NULL) {
- ret = AFPERR_MISC;
- goto exit;
- }
- if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
- LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", eaname, strerror(errno));
- switch (errno) {
- case EPERM:
- case EACCES:
- ret = AFPERR_ACCESS;
- goto exit;
- default:
- ret = AFPERR_MISC;
- goto exit;
- }
- continue;
- }
-
- count++;
- }
-
-exit:
- if (seteuid(uid) < 0) {
- LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
- exit(EXITERR_SYS);
- }
-
- if ((ea_close(&ea)) != 0) {
- LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): error closing ea handle", name);
- return AFPERR_MISC;
- }
-
- return ret;
-}
--- /dev/null
+/*
+ Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <atalk/adouble.h>
+#include <atalk/ea.h>
+#include <atalk/afp.h>
+#include <atalk/logger.h>
+#include <atalk/volume.h>
+#include <atalk/vfs.h>
+#include <atalk/util.h>
+#include <atalk/unix.h>
+
+/*
+ * Store Extended Attributes inside .AppleDouble folders as follows:
+ *
+ * filename "fileWithEAs" with EAs "testEA1" and "testEA2"
+ *
+ * - create header with with the format struct adouble_ea_ondisk, the file is written to
+ * ".AppleDouble/fileWithEAs::EA"
+ * - store EAs in files "fileWithEAs::EA::testEA1" and "fileWithEAs::EA::testEA2"
+ */
+
+/*
+ * Build mode for EA header from file mode
+ */
+static inline mode_t ea_header_mode(mode_t mode)
+{
+ /* Same as ad_hf_mode(mode) */
+ mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+ /* Owner must be able to open, read and w-lock it, in order to chmod from eg 0000 -> 0xxxx*/
+ mode |= S_IRUSR | S_IWUSR;
+ return mode;
+}
+
+/*
+ * Build mode for EA file from file mode
+ */
+static inline mode_t ea_mode(mode_t mode)
+{
+ /* Same as ad_hf_mode(mode) */
+ mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH);
+ return mode;
+}
+
+/*
+ Taken form afpd/desktop.c
+*/
+static char *mtoupath(const struct vol *vol, const char *mpath)
+{
+ static char upath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */
+ const char *m;
+ char *u;
+ size_t inplen;
+ size_t outlen;
+ uint16_t flags = CONV_ESCAPEHEX | CONV_ALLOW_COLON;
+
+ if (!mpath)
+ return NULL;
+
+ if ( *mpath == '\0' ) {
+ return( "." );
+ }
+
+ m = mpath;
+ u = upath;
+
+ inplen = strlen(m);
+ outlen = MAXPATHLEN;
+
+ if ((size_t)-1 == (outlen = convert_charset(CH_UTF8_MAC,
+ vol->v_volcharset,
+ vol->v_maccharset,
+ m, inplen, u, outlen, &flags)) ) {
+ return NULL;
+ }
+
+ return( upath );
+}
+
+
+/*
+ * Function: unpack_header
+ *
+ * Purpose: unpack and verify header file data buffer at ea->ea_data into struct ea
+ *
+ * Arguments:
+ *
+ * ea (rw) handle to struct ea
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * Verifies magic and version.
+ */
+static int unpack_header(struct ea * restrict ea)
+{
+ int ret = 0;
+ unsigned int count = 0;
+ uint32_t uint32;
+ char *buf;
+
+ /* Check magic and version */
+ buf = ea->ea_data;
+ if (*(uint32_t *)buf != htonl(EA_MAGIC)) {
+ LOG(log_error, logtype_afpd, "unpack_header: wrong magic 0x%08x", *(uint32_t *)buf);
+ ret = -1;
+ goto exit;
+ }
+ buf += 4;
+ if (*(uint16_t *)buf != htons(EA_VERSION)) {
+ LOG(log_error, logtype_afpd, "unpack_header: wrong version 0x%04x", *(uint16_t *)buf);
+ ret = -1;
+ goto exit;
+ }
+ buf += 2;
+
+ /* Get EA count */
+ ea->ea_count = ntohs(*(uint16_t *)buf);
+ LOG(log_debug, logtype_afpd, "unpack_header: number of EAs: %u", ea->ea_count);
+ buf += 2;
+
+ if (ea->ea_count == 0)
+ return 0;
+
+ /* Allocate storage for the ea_entries array */
+ ea->ea_entries = malloc(sizeof(struct ea_entry) * ea->ea_count);
+ if ( ! ea->ea_entries) {
+ LOG(log_error, logtype_afpd, "unpack_header: OOM");
+ ret = -1;
+ goto exit;
+ }
+
+ buf = ea->ea_data + EA_HEADER_SIZE;
+ while (count < ea->ea_count) {
+ memcpy(&uint32, buf, 4); /* EA size */
+ buf += 4;
+ (*(ea->ea_entries))[count].ea_size = ntohl(uint32);
+ (*(ea->ea_entries))[count].ea_name = strdup(buf);
+ if (! (*(ea->ea_entries))[count].ea_name) {
+ LOG(log_error, logtype_afpd, "unpack_header: OOM");
+ ret = -1;
+ goto exit;
+ }
+ (*(ea->ea_entries))[count].ea_namelen = strlen((*(ea->ea_entries))[count].ea_name);
+ buf += (*(ea->ea_entries))[count].ea_namelen + 1;
+
+ LOG(log_maxdebug, logtype_afpd, "unpack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
+ (*(ea->ea_entries))[count].ea_name,
+ (*(ea->ea_entries))[count].ea_size,
+ (*(ea->ea_entries))[count].ea_namelen);
+
+ count++;
+ }
+
+exit:
+ return ret;
+}
+
+/*
+ * Function: pack_header
+ *
+ * Purpose: pack everything from struct ea into buffer at ea->ea_data
+ *
+ * Arguments:
+ *
+ * ea (rw) handle to struct ea
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * adjust ea->ea_count in case an ea entry deletetion is detected
+ */
+static int pack_header(struct ea * restrict ea)
+{
+ unsigned int count = 0, eacount = 0;
+ uint16_t uint16;
+ uint32_t uint32;
+ size_t bufsize = EA_HEADER_SIZE;
+
+ char *buf = ea->ea_data + EA_HEADER_SIZE;
+
+ LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
+ ea->filename, ea->ea_count, ea->ea_size);
+
+ if (ea->ea_count == 0)
+ /* nothing to do, magic, version and count are still valid in buffer */
+ return 0;
+
+ while(count < ea->ea_count) { /* the names */
+ /* Check if its a deleted entry */
+ if ( ! ((*ea->ea_entries)[count].ea_name)) {
+ count++;
+ continue;
+ }
+
+ bufsize += (*(ea->ea_entries))[count].ea_namelen + 1;
+ count++;
+ eacount++;
+ }
+
+ bufsize += (eacount * 4); /* header + ea_size for each EA */
+ if (bufsize > ea->ea_size) {
+ /* we must realloc */
+ if ( ! (buf = realloc(ea->ea_data, bufsize)) ) {
+ LOG(log_error, logtype_afpd, "pack_header: OOM");
+ return -1;
+ }
+ ea->ea_data = buf;
+ }
+ ea->ea_size = bufsize;
+
+ /* copy count */
+ uint16 = htons(eacount);
+ memcpy(ea->ea_data + EA_COUNT_OFF, &uint16, 2);
+
+ count = 0;
+ buf = ea->ea_data + EA_HEADER_SIZE;
+ while (count < ea->ea_count) {
+ /* Check if its a deleted entry */
+ if ( ! ((*ea->ea_entries)[count].ea_name)) {
+ count++;
+ continue;
+ }
+
+ /* First: EA size */
+ uint32 = htonl((*(ea->ea_entries))[count].ea_size);
+ memcpy(buf, &uint32, 4);
+ buf += 4;
+
+ /* Second: EA name as C-string */
+ strcpy(buf, (*(ea->ea_entries))[count].ea_name);
+ buf += (*(ea->ea_entries))[count].ea_namelen + 1;
+
+ LOG(log_maxdebug, logtype_afpd, "pack_header: entry no:%u,\"%s\", size: %u, namelen: %u", count,
+ (*(ea->ea_entries))[count].ea_name,
+ (*(ea->ea_entries))[count].ea_size,
+ (*(ea->ea_entries))[count].ea_namelen);
+
+ count++;
+ }
+
+ ea->ea_count = eacount;
+
+ LOG(log_debug, logtype_afpd, "pack_header('%s'): ea_count: %u, ea_size: %u",
+ ea->filename, ea->ea_count, ea->ea_size);
+
+ return 0;
+}
+
+/*
+ * Function: ea_addentry
+ *
+ * Purpose: add one EA into ea->ea_entries[]
+ *
+ * Arguments:
+ *
+ * ea (rw) pointer to struct ea
+ * attruname (r) name of EA
+ * attrsize (r) size of ea
+ * bitmap (r) bitmap from FP func
+ *
+ * Returns: new number of EA entries, -1 on error
+ *
+ * Effects:
+ *
+ * Grow array ea->ea_entries[]. If ea->ea_entries is still NULL, start allocating.
+ * Otherwise realloc and put entry at the end. Increments ea->ea_count.
+ */
+static int ea_addentry(struct ea * restrict ea,
+ const char * restrict attruname,
+ size_t attrsize,
+ int bitmap)
+{
+ int ea_existed = 0;
+ unsigned int count = 0;
+ void *tmprealloc;
+
+ /* First check if an EA of the requested name already exist */
+ if (ea->ea_count > 0) {
+ while (count < ea->ea_count) {
+ if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
+ ea_existed = 1;
+ LOG(log_debug, logtype_afpd, "ea_addentry('%s', bitmap:0x%x): exists", attruname, bitmap);
+ if (bitmap & kXAttrCreate)
+ /* its like O_CREAT|O_EXCL -> fail */
+ return -1;
+ (*(ea->ea_entries))[count].ea_size = attrsize;
+ return 0;
+ }
+ count++;
+ }
+ }
+
+ if ((bitmap & kXAttrReplace) && ! ea_existed)
+ /* replace was requested, but EA didn't exist */
+ return -1;
+
+ if (ea->ea_count == 0) {
+ ea->ea_entries = malloc(sizeof(struct ea_entry));
+ if ( ! ea->ea_entries) {
+ LOG(log_error, logtype_afpd, "ea_addentry: OOM");
+ return -1;
+ }
+ } else if (! ea_existed) {
+ tmprealloc = realloc(ea->ea_entries, sizeof(struct ea_entry) * (ea->ea_count + 1));
+ if ( ! tmprealloc) {
+ LOG(log_error, logtype_afpd, "ea_addentry: OOM");
+ return -1;
+ }
+ ea->ea_entries = tmprealloc;
+ }
+
+ /* We've grown the array, now store the entry */
+ (*(ea->ea_entries))[ea->ea_count].ea_size = attrsize;
+ (*(ea->ea_entries))[ea->ea_count].ea_name = strdup(attruname);
+ if ( ! (*(ea->ea_entries))[ea->ea_count].ea_name) {
+ LOG(log_error, logtype_afpd, "ea_addentry: OOM");
+ goto error;
+ }
+ (*(ea->ea_entries))[ea->ea_count].ea_namelen = strlen(attruname);
+
+ ea->ea_count++;
+ return ea->ea_count;
+
+error:
+ if (ea->ea_count == 0 && ea->ea_entries) {
+ /* We just allocated storage but had an error somewhere -> free storage*/
+ free(ea->ea_entries);
+ ea->ea_entries = NULL;
+ }
+ ea->ea_count = 0;
+ return -1;
+}
+
+/*
+ * Function: create_ea_header
+ *
+ * Purpose: create EA header file, only called from ea_open
+ *
+ * Arguments:
+ *
+ * uname (r) filename for which we have to create a header
+ * ea (rw) ea handle with already allocated storage pointed to
+ * by ea->ea_data
+ *
+ * Returns: fd of open header file on success, -1 on error, errno semantics:
+ * EEXIST: open with O_CREAT | O_EXCL failed
+ *
+ * Effects:
+ *
+ * Creates EA header file and initialize ea->ea_data buffer.
+ * Possibe race condition with other afpd processes:
+ * we were called because header file didn't exist in eg. ea_open. We then
+ * try to create a file with O_CREAT | O_EXCL, but the whole process in not atomic.
+ * What do we do then? Someone else is in the process of creating the header too, but
+ * it might not have finished it. That means we cant just open, read and use it!
+ * We therefor currently just break with an error.
+ * On return the header file is still r/w locked.
+ */
+static int create_ea_header(const char * restrict uname,
+ struct ea * restrict ea)
+{
+ int fd = -1, err = 0;
+ char *ptr;
+
+ if ((fd = open(uname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
+ LOG(log_error, logtype_afpd, "ea_create: open race condition with ea header for file: %s", uname);
+ return -1;
+ }
+
+ /* lock it */
+ if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_create: lock race condition with ea header for file: %s", uname);
+ err = -1;
+ goto exit;
+ }
+
+ /* Now init it */
+ ptr = ea->ea_data;
+ *(uint32_t *)ptr = htonl(EA_MAGIC);
+ ptr += EA_MAGIC_LEN;
+ *(uint16_t *)ptr = htons(EA_VERSION);
+ ptr += EA_VERSION_LEN;
+ *(uint16_t *)ptr = 0; /* count */
+
+ ea->ea_size = EA_HEADER_SIZE;
+ ea->ea_inited = EA_INITED;
+
+exit:
+ if (err != 0) {
+ close(fd);
+ fd = -1;
+ }
+ return fd;
+}
+
+/*
+ * Function: write_ea
+ *
+ * Purpose: write an EA to disk
+ *
+ * Arguments:
+ *
+ * ea (r) struct ea handle
+ * attruname (r) EA name
+ * ibuf (r) buffer with EA content
+ * attrsize (r) size of EA
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * Creates/overwrites EA file.
+ *
+ */
+static int write_ea(const struct ea * restrict ea,
+ const char * restrict attruname,
+ const char * restrict ibuf,
+ size_t attrsize)
+{
+ int fd = -1, ret = AFP_OK;
+ struct stat st;
+ char *eaname;
+
+ if ((eaname = ea_path(ea, attruname, 1)) == NULL) {
+ LOG(log_error, logtype_afpd, "write_ea('%s'): ea_path error", attruname);
+ return AFPERR_MISC;
+ }
+
+ LOG(log_maxdebug, logtype_afpd, "write_ea('%s')", eaname);
+
+ /* Check if it exists, remove if yes*/
+ if ((stat(eaname, &st)) == 0) {
+ if ((unlink(eaname)) != 0) {
+ if (errno == EACCES)
+ return AFPERR_ACCESS;
+ else
+ return AFPERR_MISC;
+ }
+ }
+
+ if ((fd = open(eaname, O_RDWR | O_CREAT | O_EXCL, 0666 & ~ea->vol->v_umask)) == -1) {
+ LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
+ return -1;
+ }
+
+ /* lock it */
+ if ((write_lock(fd, 0, SEEK_SET, 0)) != 0) {
+ LOG(log_error, logtype_afpd, "write_ea: open race condition: %s", eaname);
+ ret = -1;
+ goto exit;
+ }
+
+ if (write(fd, ibuf, attrsize) != (ssize_t)attrsize) {
+ LOG(log_error, logtype_afpd, "write_ea('%s'): write: %s", eaname, strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+
+exit:
+ if (fd != -1)
+ close(fd); /* and unlock */
+ return ret;
+}
+
+/*
+ * Function: ea_delentry
+ *
+ * Purpose: delete one EA from ea->ea_entries[]
+ *
+ * Arguments:
+ *
+ * ea (rw) pointer to struct ea
+ * attruname (r) EA name
+ *
+ * Returns: new number of EA entries, -1 on error
+ *
+ * Effects:
+ *
+ * Remove entry from ea->ea_entries[]. Decrement ea->ea_count.
+ * Marks it as unused just by freeing name and setting it to NULL.
+ * ea_close and pack_buffer must honor this.
+ */
+static int ea_delentry(struct ea * restrict ea, const char * restrict attruname)
+{
+ int ret = 0;
+ unsigned int count = 0;
+
+ if (ea->ea_count == 0) {
+ LOG(log_error, logtype_afpd, "ea_delentry('%s'): illegal ea_count of 0 on deletion");
+ return -1;
+ }
+
+ while (count < ea->ea_count) {
+ /* search matching EA */
+ if (strcmp(attruname, (*ea->ea_entries)[count].ea_name) == 0) {
+ free((*ea->ea_entries)[count].ea_name);
+ (*ea->ea_entries)[count].ea_name = NULL;
+
+ LOG(log_debug, logtype_afpd, "ea_delentry('%s'): deleted no %u/%u",
+ attruname, count + 1, ea->ea_count);
+
+ break;
+ }
+ count++;
+ }
+
+ return ret;
+}
+
+/*
+ * Function: delete_ea_file
+ *
+ * Purpose: delete EA file from disk
+ *
+ * Arguments:
+ *
+ * ea (r) struct ea handle
+ * attruname (r) EA name
+ *
+ * Returns: 0 on success, -1 on error
+ */
+static int delete_ea_file(const struct ea * restrict ea, const char *eaname)
+{
+ int ret = 0;
+ char *eafile;
+ struct stat st;
+
+ if ((eafile = ea_path(ea, eaname, 1)) == NULL) {
+ LOG(log_error, logtype_afpd, "delete_ea_file('%s'): ea_path error", eaname);
+ return -1;
+ }
+
+ /* Check if it exists, remove if yes*/
+ if ((stat(eafile, &st)) == 0) {
+ if ((unlink(eafile)) != 0) {
+ LOG(log_error, logtype_afpd, "delete_ea_file('%s'): unlink: %s",
+ eafile, strerror(errno));
+ ret = -1;
+ } else
+ LOG(log_debug, logtype_afpd, "delete_ea_file('%s'): success", eafile);
+ }
+
+ return ret;
+}
+
+/*************************************************************************************
+ * ea_path, ea_open and ea_close are only global so that dbd can call them
+ *************************************************************************************/
+
+/*
+ * Function: ea_path
+ *
+ * Purpose: return name of ea header filename
+ *
+ * Arguments:
+ *
+ * ea (r) ea handle
+ * eaname (r) name of EA or NULL
+ * macname (r) if != 0 call mtoupath on eaname
+ *
+ * Returns: pointer to name in static buffer, NULL on error
+ *
+ * Effects:
+ *
+ * Calls ad_open, copies buffer, appends "::EA" and if supplied append eanme
+ * Files: "file" -> "file/.AppleDouble/file::EA"
+ * Dirs: "dir" -> "dir/.AppleDouble/.Parent::EA"
+ * "file" with EA "myEA" -> "file/.AppleDouble/file::EA:myEA"
+ */
+char *ea_path(const struct ea * restrict ea, const char * restrict eaname, int macname)
+{
+ const char *adname;
+ static char pathbuf[MAXPATHLEN + 1];
+
+ /* get name of a adouble file from uname */
+ adname = ea->vol->ad_path(ea->filename, (ea->ea_flags & EA_DIR) ? ADFLAGS_DIR : 0);
+ /* copy it so we can work with it */
+ strlcpy(pathbuf, adname, MAXPATHLEN + 1);
+ /* append "::EA" */
+ strlcat(pathbuf, "::EA", MAXPATHLEN + 1);
+
+ if (eaname) {
+ strlcat(pathbuf, "::", MAXPATHLEN + 1);
+ if (macname)
+ if ((eaname = mtoupath(ea->vol, eaname)) == NULL)
+ return NULL;
+ strlcat(pathbuf, eaname, MAXPATHLEN + 1);
+ }
+
+ return pathbuf;
+}
+
+/*
+ * Function: ea_open
+ *
+ * Purpose: open EA header file, create if it doesnt exits and called with O_CREATE
+ *
+ * Arguments:
+ *
+ * vol (r) current volume
+ * uname (r) filename for which we have to open a header
+ * flags (r) EA_CREATE: create if it doesn't exist (without it won't be created)
+ * EA_RDONLY: open read only
+ * EA_RDWR: open read/write
+ * Eiterh EA_RDONLY or EA_RDWR MUST be requested
+ * ea (w) pointer to a struct ea that we fill
+ *
+ * Returns: 0 on success
+ * -1 on misc error with errno = EFAULT
+ * -2 if no EA header exists with errno = ENOENT
+ *
+ * Effects:
+ *
+ * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
+ * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
+ * file is either read or write locked depending on the open flags.
+ * When you're done with struct ea you must call ea_close on it.
+ */
+int ea_open(const struct vol * restrict vol,
+ const char * restrict uname,
+ eaflags_t eaflags,
+ struct ea * restrict ea)
+{
+ int ret = 0;
+ char *eaname;
+ struct stat st;
+
+ /* Enforce usage rules! */
+ if ( ! (eaflags & (EA_RDONLY | EA_RDWR))) {
+ LOG(log_error, logtype_afpd, "ea_open: called without EA_RDONLY | EA_RDWR", uname);
+ return -1;
+ }
+
+ /* Set it all to 0 */
+ memset(ea, 0, sizeof(struct ea));
+
+ ea->vol = vol; /* ea_close needs it */
+ ea->ea_flags = eaflags;
+ ea->dirfd = -1; /* no *at (cf openat) semantics by default */
+
+ /* Dont care for errors, eg when removing the file is already gone */
+ if (!stat(uname, &st) && S_ISDIR(st.st_mode))
+ ea->ea_flags |= EA_DIR;
+
+ if ( ! (ea->filename = strdup(uname))) {
+ LOG(log_error, logtype_afpd, "ea_open: OOM");
+ return -1;
+ }
+
+ eaname = ea_path(ea, NULL, 0);
+ LOG(log_maxdebug, logtype_afpd, "ea_open: ea_path: %s", eaname);
+
+ /* Check if it exists, if not create it if EA_CREATE is in eaflags */
+ if ((stat(eaname, &st)) != 0) {
+ if (errno == ENOENT) {
+
+ /* It doesnt exist */
+
+ if ( ! (eaflags & EA_CREATE)) {
+ /* creation was not requested, so return with error */
+ ret = -2;
+ goto exit;
+ }
+
+ /* Now create a header file */
+
+ /* malloc buffer for minimal on disk data */
+ ea->ea_data = malloc(EA_HEADER_SIZE);
+ if (! ea->ea_data) {
+ LOG(log_error, logtype_afpd, "ea_open: OOM");
+ ret = -1;
+ goto exit;
+ }
+
+ /* create it */
+ ea->ea_fd = create_ea_header(eaname, ea);
+ if (ea->ea_fd == -1) {
+ ret = -1;
+ goto exit;
+ }
+
+ return 0;
+
+ } else {/* errno != ENOENT */
+ ret = -1;
+ goto exit;
+ }
+ }
+
+ /* header file exists, so read and parse it */
+
+ /* malloc buffer where we read disk file into */
+ if (st.st_size < EA_HEADER_SIZE) {
+ LOG(log_error, logtype_afpd, "ea_open('%s'): bogus EA header file", eaname);
+ ret = -1;
+ goto exit;
+ }
+ ea->ea_size = st.st_size;
+ ea->ea_data = malloc(st.st_size);
+ if (! ea->ea_data) {
+ LOG(log_error, logtype_afpd, "ea_open: OOM");
+ ret = -1;
+ goto exit;
+ }
+
+ /* Now lock, open and read header file from disk */
+ if ((ea->ea_fd = open(eaname, (ea->ea_flags & EA_RDWR) ? O_RDWR : O_RDONLY)) == -1) {
+ LOG(log_error, logtype_afpd, "ea_open('%s'): error: %s", eaname, strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+
+ /* lock it */
+ if (ea->ea_flags & EA_RDONLY) {
+ /* read lock */
+ if ((read_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_open: lock error on header: %s", eaname);
+ ret = -1;
+ goto exit;
+ }
+ } else { /* EA_RDWR */
+ /* write lock */
+ if ((write_lock(ea->ea_fd, 0, SEEK_SET, 0)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_open: lock error on header: %s", eaname);
+ ret = -1;
+ goto exit;
+ }
+ }
+
+ /* read it */
+ if (read(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
+ LOG(log_error, logtype_afpd, "ea_open: short read on header: %s", eaname);
+ ret = -1;
+ goto exit;
+ }
+
+ if ((unpack_header(ea)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_open: error unpacking header for: %s", eaname);
+ ret = -1;
+ goto exit;
+ }
+
+exit:
+ switch (ret) {
+ case 0:
+ ea->ea_inited = EA_INITED;
+ break;
+ case -1:
+ errno = EFAULT; /* force some errno distinguishable from ENOENT */
+ /* fall through */
+ case -2:
+ if (ea->ea_data) {
+ free(ea->ea_data);
+ ea->ea_data = NULL;
+ }
+ if (ea->ea_fd) {
+ close(ea->ea_fd);
+ ea->ea_fd = -1;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Function: ea_openat
+ *
+ * Purpose: openat like wrapper for ea_open, takes a additional file descriptor
+ *
+ * Arguments:
+ *
+ * vol (r) current volume
+ * sfd (r) openat like file descriptor
+ * uname (r) filename for which we have to open a header
+ * flags (r) EA_CREATE: create if it doesn't exist (without it won't be created)
+ * EA_RDONLY: open read only
+ * EA_RDWR: open read/write
+ * Eiterh EA_RDONLY or EA_RDWR MUST be requested
+ * ea (w) pointer to a struct ea that we fill
+ *
+ * Returns: 0 on success
+ * -1 on misc error with errno = EFAULT
+ * -2 if no EA header exists with errno = ENOENT
+ *
+ * Effects:
+ *
+ * opens header file and stores fd in ea->ea_fd. Size of file is put into ea->ea_size.
+ * number of EAs is stored in ea->ea_count. flags are remembered in ea->ea_flags.
+ * file is either read or write locked depending on the open flags.
+ * When you're done with struct ea you must call ea_close on it.
+ */
+int ea_openat(const struct vol * restrict vol,
+ int dirfd,
+ const char * restrict uname,
+ eaflags_t eaflags,
+ struct ea * restrict ea)
+{
+ int ret = 0;
+ int cwdfd = -1;
+
+ if (dirfd != -1) {
+ if (((cwdfd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+ ret = -1;
+ goto exit;
+ }
+ }
+
+ ret = ea_open(vol, uname, eaflags, ea);
+ ea->dirfd = dirfd;
+
+ if (dirfd != -1) {
+ if (fchdir(cwdfd) != 0) {
+ LOG(log_error, logtype_afpd, "ea_openat: cant chdir back, exiting");
+ exit(EXITERR_SYS);
+ }
+ }
+
+
+exit:
+ if (cwdfd != -1)
+ close(cwdfd);
+
+ return ret;
+
+}
+
+/*
+ * Function: ea_close
+ *
+ * Purpose: flushes and closes an ea handle
+ *
+ * Arguments:
+ *
+ * ea (rw) pointer to ea handle
+ *
+ * Returns: 0 on success, -1 on error
+ *
+ * Effects:
+ *
+ * Flushes and then closes and frees all resouces held by ea handle.
+ * Pack data in ea into ea_data, then write ea_data to disk
+ */
+int ea_close(struct ea * restrict ea)
+{
+ int ret = 0;
+ unsigned int count = 0;
+ char *eaname;
+ struct stat st;
+
+ LOG(log_debug, logtype_afpd, "ea_close('%s')", ea->filename);
+
+ if (ea->ea_inited != EA_INITED) {
+ LOG(log_warning, logtype_afpd, "ea_close('%s'): non initialized ea", ea->filename);
+ return 0;
+ }
+
+ /* pack header and write it to disk if it was opened EA_RDWR*/
+ if (ea->ea_flags & EA_RDWR) {
+ if ((pack_header(ea)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_close: pack header");
+ ret = -1;
+ } else {
+ if (ea->ea_count == 0) {
+ /* Check if EA header exists and remove it */
+ eaname = ea_path(ea, NULL, 0);
+ if ((lstatat(ea->dirfd, eaname, &st)) == 0) {
+ if ((netatalk_unlinkat(ea->dirfd, eaname)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_close('%s'): unlink: %s",
+ eaname, strerror(errno));
+ ret = -1;
+ }
+ else
+ LOG(log_debug, logtype_afpd, "ea_close(unlink '%s'): success", eaname);
+ } else {
+ /* stat error */
+ if (errno != ENOENT) {
+ LOG(log_error, logtype_afpd, "ea_close('%s'): stat: %s",
+ eaname, strerror(errno));
+ ret = -1;
+ }
+ }
+ } else { /* ea->ea_count > 0 */
+ if ((lseek(ea->ea_fd, 0, SEEK_SET)) == -1) {
+ LOG(log_error, logtype_afpd, "ea_close: lseek: %s", strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+
+ if ((ftruncate(ea->ea_fd, 0)) == -1) {
+ LOG(log_error, logtype_afpd, "ea_close: ftruncate: %s", strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+
+ if (write(ea->ea_fd, ea->ea_data, ea->ea_size) != (ssize_t)ea->ea_size) {
+ LOG(log_error, logtype_afpd, "ea_close: write: %s", strerror(errno));
+ ret = -1;
+ }
+ }
+ }
+ }
+
+exit:
+ /* free names */
+ while(count < ea->ea_count) {
+ if ( (*ea->ea_entries)[count].ea_name ) {
+ free((*ea->ea_entries)[count].ea_name);
+ (*ea->ea_entries)[count].ea_name = NULL;
+ }
+ count++;
+ }
+ ea->ea_count = 0;
+
+ if (ea->filename) {
+ free(ea->filename);
+ ea->filename = NULL;
+ }
+
+ if (ea->ea_entries) {
+ free(ea->ea_entries);
+ ea->ea_entries = NULL;
+ }
+
+ if (ea->ea_data) {
+ free(ea->ea_data);
+ ea->ea_data = NULL;
+ }
+ if (ea->ea_fd != -1) {
+ close(ea->ea_fd); /* also releases the fcntl lock */
+ ea->ea_fd = -1;
+ }
+
+ return 0;
+}
+
+
+
+/************************************************************************************
+ * VFS funcs called from afp_ea* funcs
+ ************************************************************************************/
+
+/*
+ * Function: get_easize
+ *
+ * Purpose: get size of an EA
+ *
+ * Arguments:
+ *
+ * vol (r) current volume
+ * rbuf (w) DSI reply buffer
+ * rbuflen (rw) current length of data in reply buffer
+ * uname (r) filename
+ * oflag (r) link and create flag
+ * attruname (r) name of attribute
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies EA size into rbuf in network order. Increments *rbuflen +4.
+ */
+int get_easize(VFS_FUNC_ARGS_EA_GETSIZE)
+{
+ int ret = AFPERR_MISC;
+ unsigned int count = 0;
+ uint32_t uint32;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "get_easize: file: %s", uname);
+
+ if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
+ if (errno != ENOENT)
+ LOG(log_error, logtype_afpd, "get_easize: error calling ea_open for file: %s", uname);
+
+ memset(rbuf, 0, 4);
+ *rbuflen += 4;
+ return ret;
+ }
+
+ while (count < ea.ea_count) {
+ if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
+ uint32 = htonl((*ea.ea_entries)[count].ea_size);
+ memcpy(rbuf, &uint32, 4);
+ *rbuflen += 4;
+ ret = AFP_OK;
+
+ LOG(log_debug, logtype_afpd, "get_easize(\"%s\"): size: %u",
+ attruname, (*ea.ea_entries)[count].ea_size);
+ break;
+ }
+ count++;
+ }
+
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "get_easize: error closing ea handle for file: %s", uname);
+ return AFPERR_MISC;
+ }
+
+ return ret;
+}
+
+/*
+ * Function: get_eacontent
+ *
+ * Purpose: copy EA into rbuf
+ *
+ * Arguments:
+ *
+ * vol (r) current volume
+ * rbuf (w) DSI reply buffer
+ * rbuflen (rw) current length of data in reply buffer
+ * uname (r) filename
+ * oflag (r) link and create flag
+ * attruname (r) name of attribute
+ * maxreply (r) maximum EA size as of current specs/real-life
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies EA into rbuf. Increments *rbuflen accordingly.
+ */
+int get_eacontent(VFS_FUNC_ARGS_EA_GETCONTENT)
+{
+ int ret = AFPERR_MISC, fd = -1;
+ unsigned int count = 0;
+ uint32_t uint32;
+ size_t toread;
+ struct ea ea;
+ char *eafile;
+
+ LOG(log_debug, logtype_afpd, "get_eacontent('%s/%s')", uname, attruname);
+
+ if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
+ if (errno != ENOENT)
+ LOG(log_error, logtype_afpd, "get_eacontent('%s'): ea_open error", uname);
+ memset(rbuf, 0, 4);
+ *rbuflen += 4;
+ return ret;
+ }
+
+ while (count < ea.ea_count) {
+ if (strcmp(attruname, (*ea.ea_entries)[count].ea_name) == 0) {
+ if ( (eafile = ea_path(&ea, attruname, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ break;
+ }
+
+ if ((fd = open(eafile, O_RDONLY)) == -1) {
+ LOG(log_error, logtype_afpd, "get_eacontent('%s'): open error: %s", uname, strerror(errno));
+ ret = AFPERR_MISC;
+ break;
+ }
+
+ /* Check how much the client wants, give him what we think is right */
+ maxreply -= MAX_REPLY_EXTRA_BYTES;
+ if (maxreply > MAX_EA_SIZE)
+ maxreply = MAX_EA_SIZE;
+ toread = (maxreply < (*ea.ea_entries)[count].ea_size) ? maxreply : (*ea.ea_entries)[count].ea_size;
+ LOG(log_debug, logtype_afpd, "get_eacontent('%s'): sending %u bytes", attruname, toread);
+
+ /* Put length of EA data in reply buffer */
+ uint32 = htonl(toread);
+ memcpy(rbuf, &uint32, 4);
+ rbuf += 4;
+ *rbuflen += 4;
+
+ if (read(fd, rbuf, toread) != (ssize_t)toread) {
+ LOG(log_error, logtype_afpd, "get_eacontent('%s/%s'): short read", uname, attruname);
+ close(fd);
+ ret = AFPERR_MISC;
+ break;
+ }
+ *rbuflen += toread;
+ close(fd);
+
+ ret = AFP_OK;
+ break;
+ }
+ count++;
+ }
+
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "get_eacontent('%s'): error closing ea handle", uname);
+ return AFPERR_MISC;
+ }
+
+ return ret;
+
+}
+
+/*
+ * Function: list_eas
+ *
+ * Purpose: copy names of EAs into attrnamebuf
+ *
+ * Arguments:
+ *
+ * vol (r) current volume
+ * attrnamebuf (w) store names a consecutive C strings here
+ * buflen (rw) length of names in attrnamebuf
+ * uname (r) filename
+ * oflag (r) link and create flag
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies names of all EAs of uname as consecutive C strings into rbuf.
+ * Increments *buflen accordingly.
+ */
+int list_eas(VFS_FUNC_ARGS_EA_LIST)
+{
+ unsigned int count = 0;
+ int attrbuflen = *buflen, ret = AFP_OK, len;
+ char *buf = attrnamebuf;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "list_eas: file: %s", uname);
+
+ if ((ea_open(vol, uname, EA_RDONLY, &ea)) != 0) {
+ if (errno != ENOENT) {
+ LOG(log_error, logtype_afpd, "list_eas: error calling ea_open for file: %s", uname);
+ return AFPERR_MISC;
+ }
+ else
+ return AFP_OK;
+ }
+
+ while (count < ea.ea_count) {
+ /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
+ if ( ( len = convert_string(vol->v_volcharset,
+ CH_UTF8_MAC,
+ (*ea.ea_entries)[count].ea_name,
+ (*ea.ea_entries)[count].ea_namelen,
+ buf + attrbuflen,
+ 255))
+ <= 0 ) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ if (len == 255)
+ /* convert_string didn't 0-terminate */
+ attrnamebuf[attrbuflen + 255] = 0;
+
+ LOG(log_debug7, logtype_afpd, "list_eas(%s): EA: %s",
+ uname, (*ea.ea_entries)[count].ea_name);
+
+ attrbuflen += len + 1;
+ if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
+ /* Next EA name could overflow, so bail out with error.
+ FIXME: evantually malloc/memcpy/realloc whatever.
+ Is it worth it ? */
+ LOG(log_warning, logtype_afpd, "list_eas(%s): running out of buffer for EA names", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ count++;
+ }
+
+exit:
+ *buflen = attrbuflen;
+
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "list_eas: error closing ea handle for file: %s", uname);
+ return AFPERR_MISC;
+ }
+
+ return ret;
+}
+
+/*
+ * Function: set_ea
+ *
+ * Purpose: set a Solaris native EA
+ *
+ * Arguments:
+ *
+ * vol (r) current volume
+ * uname (r) filename
+ * attruname (r) EA name
+ * ibuf (r) buffer with EA content
+ * attrsize (r) length EA in ibuf
+ * oflag (r) link and create flag
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Copies names of all EAs of uname as consecutive C strings into rbuf.
+ * Increments *rbuflen accordingly.
+ */
+int set_ea(VFS_FUNC_ARGS_EA_SET)
+{
+ int ret = AFP_OK;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "set_ea: file: %s", uname);
+
+ if ((ea_open(vol, uname, EA_CREATE | EA_RDWR, &ea)) != 0) {
+ LOG(log_error, logtype_afpd, "set_ea('%s'): ea_open error", uname);
+ return AFPERR_MISC;
+ }
+
+ if ((ea_addentry(&ea, attruname, attrsize, oflag)) == -1) {
+ LOG(log_error, logtype_afpd, "set_ea('%s'): ea_addentry error", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ if ((write_ea(&ea, attruname, ibuf, attrsize)) != 0) {
+ LOG(log_error, logtype_afpd, "set_ea('%s'): write_ea error", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+exit:
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "set_ea('%s'): ea_close error", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ return ret;
+}
+
+/*
+ * Function: remove_ea
+ *
+ * Purpose: remove a EA from a file
+ *
+ * Arguments:
+ *
+ * vol (r) current volume
+ * uname (r) filename
+ * attruname (r) EA name
+ * oflag (r) link and create flag
+ *
+ * Returns: AFP code: AFP_OK on success or appropiate AFP error code
+ *
+ * Effects:
+ *
+ * Removes EA attruname from file uname.
+ */
+int remove_ea(VFS_FUNC_ARGS_EA_REMOVE)
+{
+ int ret = AFP_OK;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "remove_ea('%s/%s')", uname, attruname);
+
+ if ((ea_open(vol, uname, EA_RDWR, &ea)) != 0) {
+ LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_open error", uname);
+ return AFPERR_MISC;
+ }
+
+ if ((ea_delentry(&ea, attruname)) == -1) {
+ LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_delentry error", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ if ((delete_ea_file(&ea, attruname)) != 0) {
+ LOG(log_error, logtype_afpd, "remove_ea('%s'): delete_ea error", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+exit:
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "remove_ea('%s'): ea_close error", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ return ret;
+}
+
+/******************************************************************************************
+ * EA VFS funcs that deal with file/dir cp/mv/rm
+ ******************************************************************************************/
+
+int ea_deletefile(VFS_FUNC_ARGS_DELETEFILE)
+{
+ unsigned int count = 0;
+ int ret = AFP_OK;
+ int cwd = -1;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "ea_deletefile('%s')", file);
+
+ /* Open EA stuff */
+ if ((ea_openat(vol, dirfd, file, EA_RDWR, &ea)) != 0) {
+ if (errno == ENOENT)
+ /* no EA files, nothing to do */
+ return AFP_OK;
+ else {
+ LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error calling ea_open", file);
+ return AFPERR_MISC;
+ }
+ }
+
+ if (dirfd != -1) {
+ if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ }
+
+ while (count < ea.ea_count) {
+ if ((delete_ea_file(&ea, (*ea.ea_entries)[count].ea_name)) != 0) {
+ ret = AFPERR_MISC;
+ continue;
+ }
+ free((*ea.ea_entries)[count].ea_name);
+ (*ea.ea_entries)[count].ea_name = NULL;
+ count++;
+ }
+
+ /* ea_close removes the EA header file for us because all names are NULL */
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_deletefile('%s'): error closing ea handle", file);
+ ret = AFPERR_MISC;
+ }
+
+ if (dirfd != -1 && fchdir(cwd) != 0) {
+ LOG(log_error, logtype_afpd, "ea_deletefile: cant chdir back. exit!");
+ exit(EXITERR_SYS);
+ }
+
+exit:
+ if (cwd != -1)
+ close(cwd);
+
+ return ret;
+}
+
+int ea_renamefile(VFS_FUNC_ARGS_RENAMEFILE)
+{
+ unsigned int count = 0;
+ int ret = AFP_OK;
+ size_t easize;
+ char srceapath[ MAXPATHLEN + 1];
+ char *eapath;
+ char *eaname;
+ struct ea srcea;
+ struct ea dstea;
+ struct adouble ad;
+
+ LOG(log_debug, logtype_afpd, "ea_renamefile('%s'/'%s')", src, dst);
+
+
+ /* Open EA stuff */
+ if ((ea_openat(vol, dirfd, src, EA_RDWR, &srcea)) != 0) {
+ if (errno == ENOENT)
+ /* no EA files, nothing to do */
+ return AFP_OK;
+ else {
+ LOG(log_error, logtype_afpd, "ea_renamefile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
+ return AFPERR_MISC;
+ }
+ }
+
+ if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+ if (errno == ENOENT) {
+ /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ if ((ad_open(&ad, dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): ad_open error: '%s'", src, dst, dst);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ ad_close(&ad, ADFLAGS_HF);
+ if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ }
+ }
+
+ /* Loop through all EAs: */
+ while (count < srcea.ea_count) {
+ /* Move EA */
+ eaname = (*srcea.ea_entries)[count].ea_name;
+ easize = (*srcea.ea_entries)[count].ea_size;
+
+ /* Build src and dst paths for rename() */
+ if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ strcpy(srceapath, eapath);
+ if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ LOG(log_maxdebug, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+ src, dst, srceapath, eapath);
+
+ /* Add EA to dstea */
+ if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
+ LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+ src, dst, srceapath, eapath);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ /* Remove EA entry from srcea */
+ if ((ea_delentry(&srcea, eaname)) == -1) {
+ LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+ src, dst, srceapath, eapath);
+ ea_delentry(&dstea, eaname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ /* Now rename the EA */
+ if ((unix_rename(dirfd, srceapath, -1, eapath)) < 0) {
+ LOG(log_error, logtype_afpd, "ea_renamefile('%s/%s'): moving EA '%s' to '%s'",
+ src, dst, srceapath, eapath);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ count++;
+ }
+
+
+exit:
+ ea_close(&srcea);
+ ea_close(&dstea);
+ return ret;
+}
+
+int ea_copyfile(VFS_FUNC_ARGS_COPYFILE)
+{
+ unsigned int count = 0;
+ int ret = AFP_OK;
+ size_t easize;
+ char srceapath[ MAXPATHLEN + 1];
+ char *eapath;
+ char *eaname;
+ struct ea srcea;
+ struct ea dstea;
+ struct adouble ad;
+
+ LOG(log_debug, logtype_afpd, "ea_copyfile('%s'/'%s')", src, dst);
+
+ /* Open EA stuff */
+ if ((ea_openat(vol, sfd, src, EA_RDWR, &srcea)) != 0) {
+ if (errno == ENOENT)
+ /* no EA files, nothing to do */
+ return AFP_OK;
+ else {
+ LOG(log_error, logtype_afpd, "ea_copyfile('%s'/'%s'): ea_open error: '%s'", src, dst, src);
+ return AFPERR_MISC;
+ }
+ }
+
+ if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+ if (errno == ENOENT) {
+ /* Possibly the .AppleDouble folder didn't exist, we create it and try again */
+ ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ if ((ad_open(&ad, dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ad_open error: '%s'", src, dst, dst);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ ad_close(&ad, ADFLAGS_HF);
+ if ((ea_open(vol, dst, EA_RDWR | EA_CREATE, &dstea)) != 0) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ }
+ }
+
+ /* Loop through all EAs: */
+ while (count < srcea.ea_count) {
+ /* Copy EA */
+ eaname = (*srcea.ea_entries)[count].ea_name;
+ easize = (*srcea.ea_entries)[count].ea_size;
+
+ /* Build src and dst paths for copy_file() */
+ if ((eapath = ea_path(&srcea, eaname, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ strcpy(srceapath, eapath);
+ if ((eapath = ea_path(&dstea, eaname, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ LOG(log_maxdebug, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
+ src, dst, srceapath, eapath);
+
+ /* Add EA to dstea */
+ if ((ea_addentry(&dstea, eaname, easize, 0)) == -1) {
+ LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): ea_addentry('%s') error",
+ src, dst, eaname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ /* Now copy the EA */
+ if ((copy_file(sfd, srceapath, eapath, (0666 & ~vol->v_umask))) < 0) {
+ LOG(log_error, logtype_afpd, "ea_copyfile('%s/%s'): copying EA '%s' to '%s'",
+ src, dst, srceapath, eapath);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+
+ count++;
+ }
+
+exit:
+ ea_close(&srcea);
+ ea_close(&dstea);
+ return ret;
+}
+
+int ea_chown(VFS_FUNC_ARGS_CHOWN)
+{
+
+ unsigned int count = 0;
+ int ret = AFP_OK;
+ char *eaname;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "ea_chown('%s')", path);
+ /* Open EA stuff */
+ if ((ea_open(vol, path, EA_RDWR, &ea)) != 0) {
+ if (errno == ENOENT)
+ /* no EA files, nothing to do */
+ return AFP_OK;
+ else {
+ LOG(log_error, logtype_afpd, "ea_chown('%s'): error calling ea_open", path);
+ return AFPERR_MISC;
+ }
+ }
+
+ if ((lchown(ea_path(&ea, NULL, 0), uid, gid)) != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = AFPERR_ACCESS;
+ goto exit;
+ default:
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ }
+
+ while (count < ea.ea_count) {
+ if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ if ((lchown(eaname, uid, gid)) != 0) {
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = AFPERR_ACCESS;
+ goto exit;
+ default:
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ continue;
+ }
+
+ count++;
+ }
+
+exit:
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_chown('%s'): error closing ea handle", path);
+ return AFPERR_MISC;
+ }
+
+ return ret;
+}
+
+int ea_chmod_file(VFS_FUNC_ARGS_SETFILEMODE)
+{
+
+ unsigned int count = 0;
+ int ret = AFP_OK;
+ const char *eaname;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "ea_chmod_file('%s')", name);
+ /* Open EA stuff */
+ if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
+ if (errno == ENOENT)
+ /* no EA files, nothing to do */
+ return AFP_OK;
+ else
+ return AFPERR_MISC;
+ }
+
+ /* Set mode on EA header file */
+ if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = AFPERR_ACCESS;
+ goto exit;
+ default:
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ }
+
+ /* Set mode on EA files */
+ while (count < ea.ea_count) {
+ if ((eaname = ea_path(&ea, (*ea.ea_entries)[count].ea_name, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): %s", eaname, strerror(errno));
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = AFPERR_ACCESS;
+ goto exit;
+ default:
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ continue;
+ }
+
+ count++;
+ }
+
+exit:
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_chmod_file('%s'): error closing ea handle", name);
+ return AFPERR_MISC;
+ }
+
+ return ret;
+}
+
+int ea_chmod_dir(VFS_FUNC_ARGS_SETDIRUNIXMODE)
+{
+
+ int ret = AFP_OK;
+ unsigned int count = 0;
+ uid_t uid;
+ const char *eaname;
+ const char *eaname_safe = NULL;
+ struct ea ea;
+
+ LOG(log_debug, logtype_afpd, "ea_chmod_dir('%s')", name);
+ /* .AppleDouble already might be inaccesible, so we must run as id 0 */
+ uid = geteuid();
+ if (seteuid(0)) {
+ LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): seteuid: %s", name, strerror(errno));
+ return AFPERR_MISC;
+ }
+
+ /* Open EA stuff */
+ if ((ea_open(vol, name, EA_RDWR, &ea)) != 0) {
+ /* ENOENT --> no EA files, nothing to do */
+ if (errno != ENOENT)
+ ret = AFPERR_MISC;
+ if (seteuid(uid) < 0) {
+ LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
+ exit(EXITERR_SYS);
+ }
+ return ret;
+ }
+
+ /* Set mode on EA header */
+ if ((setfilmode(ea_path(&ea, NULL, 0), ea_header_mode(mode), NULL, vol->v_umask)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", ea_path(&ea, NULL, 0), strerror(errno));
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = AFPERR_ACCESS;
+ goto exit;
+ default:
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ }
+
+ /* Set mode on EA files */
+ while (count < ea.ea_count) {
+ eaname = (*ea.ea_entries)[count].ea_name;
+ /*
+ * Be careful with EA names from the EA header!
+ * Eg NFS users might have access to them, can inject paths using ../ or /.....
+ * FIXME:
+ * Until the EA code escapes / in EA name requests from the client, these therefor wont work.
+ */
+ if ((eaname_safe = strrchr(eaname, '/'))) {
+ LOG(log_warning, logtype_afpd, "ea_chmod_dir('%s'): contains a slash", eaname);
+ eaname = eaname_safe;
+ }
+ if ((eaname = ea_path(&ea, eaname, 1)) == NULL) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ if ((setfilmode(eaname, ea_mode(mode), NULL, vol->v_umask)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): %s", eaname, strerror(errno));
+ switch (errno) {
+ case EPERM:
+ case EACCES:
+ ret = AFPERR_ACCESS;
+ goto exit;
+ default:
+ ret = AFPERR_MISC;
+ goto exit;
+ }
+ continue;
+ }
+
+ count++;
+ }
+
+exit:
+ if (seteuid(uid) < 0) {
+ LOG(log_error, logtype_afpd, "can't seteuid back: %s", strerror(errno));
+ exit(EXITERR_SYS);
+ }
+
+ if ((ea_close(&ea)) != 0) {
+ LOG(log_error, logtype_afpd, "ea_chmod_dir('%s'): error closing ea handle", name);
+ return AFPERR_MISC;
+ }
+
+ return ret;
+}
/*
- $Id: ea_sys.c,v 1.8 2010-04-13 08:05:06 franklahm Exp $
Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
This program is free software; you can redistribute it and/or modify
#include <fcntl.h>
#include <dirent.h>
-#if HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#elif HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
-#endif
-
-#ifdef HAVE_SYS_EA_H
-#include <sys/ea.h>
-#endif
-
-#ifdef HAVE_SYS_EXTATTR_H
-#include <sys/extattr.h>
-#endif
-
#include <atalk/adouble.h>
#include <atalk/ea.h>
#include <atalk/afp.h>
#include <atalk/unix.h>
#include <atalk/compat.h>
-#ifndef ENOATTR
-#define ENOATTR ENODATA
-#endif
-
-
/**********************************************************************************
* EA VFS funcs for storing EAs in nativa filesystem EAs
**********************************************************************************/
*
* Copies names of all EAs of uname as consecutive C strings into rbuf.
* Increments *rbuflen accordingly.
+ * We hide the adouble:ea extended attributes here, but we currently
+ * allow reading, writing and deleteting them.
*/
int sys_list_eas(VFS_FUNC_ARGS_EA_LIST)
{
ptr = buf;
while (ret > 0) {
len = strlen(ptr);
+ if (NOT_NETATALK_EA(ptr)) {
+ /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
+ if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
+ ret = AFPERR_MISC;
+ goto exit;
+ }
- /* Convert name to CH_UTF8_MAC and directly store in in the reply buffer */
- if ( 0 >= ( nlen = convert_string(vol->v_volcharset, CH_UTF8_MAC, ptr, len, attrnamebuf + attrbuflen, 256)) ) {
- ret = AFPERR_MISC;
- goto exit;
- }
-
- LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr);
+ LOG(log_debug7, logtype_afpd, "sys_list_extattr(%s): attribute: %s", uname, ptr);
- attrbuflen += nlen + 1;
- if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
- /* Next EA name could overflow, so bail out with error.
- FIXME: evantually malloc/memcpy/realloc whatever.
- Is it worth it ? */
- LOG(log_warning, logtype_afpd, "sys_list_extattr(%s): running out of buffer for EA names", uname);
- ret = AFPERR_MISC;
- goto exit;
+ attrbuflen += nlen + 1;
+ if (attrbuflen > (ATTRNAMEBUFSIZ - 256)) {
+ /* Next EA name could overflow, so bail out with error.
+ FIXME: evantually malloc/memcpy/realloc whatever.
+ Is it worth it ? */
+ LOG(log_warning, logtype_afpd, "sys_list_extattr(%s): running out of buffer for EA names", uname);
+ ret = AFPERR_MISC;
+ goto exit;
+ }
}
- ret -= len +1;
- ptr += len +1;
+ ret -= len + 1;
+ ptr += len + 1;
}
ret = AFP_OK;
--- /dev/null
+/*
+ Unix SMB/CIFS implementation.
+ Samba system utilities
+ Copyright (C) Andrew Tridgell 1992-1998
+ Copyright (C) Jeremy Allison 1998-2005
+ Copyright (C) Timur Bakeyev 2005
+ Copyright (C) Bjoern Jacke 2006-2007
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ sys_copyxattr modified from LGPL2.1 libattr copyright
+ Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved.
+ Copyright (C) 2001 Andreas Gruenbacher.
+
+ Samba 3.0.28, modified for netatalk.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#elif HAVE_SYS_XATTR_H
+#include <sys/xattr.h>
+#endif
+
+#ifdef HAVE_SYS_EA_H
+#include <sys/ea.h>
+#endif
+
+#ifdef HAVE_ATTROPEN
+
+#include <dirent.h>
+#endif
+
+#ifdef HAVE_SYS_EXTATTR_H
+#include <sys/extattr.h>
+#endif
+
+#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/logger.h>
+#include <atalk/ea.h>
+
+/******** Solaris EA helper function prototypes ********/
+#ifdef HAVE_ATTROPEN
+#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
+static int solaris_write_xattr(int attrfd, const char *value, size_t size);
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
+static int solaris_unlinkat(int attrdirfd, const char *name);
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
+#endif
+
+/**************************************************************************
+ Wrappers for extented attribute calls. Based on the Linux package with
+ support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
+****************************************************************************/
+static char attr_name[256 +5] = "user.";
+
+static const char *prefix(const char *uname)
+{
+#if defined(HAVE_ATTROPEN)
+ return uname;
+#else
+ strlcpy(attr_name +5, uname, 256);
+ return attr_name;
+#endif
+}
+
+ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
+{
+ const char *name = prefix(uname);
+
+#if defined(HAVE_GETXATTR)
+#ifndef XATTR_ADD_OPT
+ return getxattr(path, name, value, size);
+#else
+ int options = 0;
+ return getxattr(path, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_GETEA)
+ return getea(path, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_FILE)
+ ssize_t retval;
+ /*
+ * The BSD implementation has a nasty habit of silently truncating
+ * the returned value to the size of the buffer, so we have to check
+ * that the buffer is large enough to fit the returned value.
+ */
+ if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
+ if (size == 0)
+ /* size == 0 means only return size */
+ return retval;
+ if (retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
+ return retval;
+ }
+
+ LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
+ return -1;
+#elif defined(HAVE_ATTR_GET)
+ int retval, flags = 0;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
+
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t sys_fgetxattr (int filedes, const char *uname, void *value, size_t size)
+{
+ const char *name = prefix(uname);
+
+#if defined(HAVE_FGETXATTR)
+#ifndef XATTR_ADD_OPT
+ return fgetxattr(filedes, name, value, size);
+#else
+ int options = 0;
+ return fgetxattr(filedes, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_FGETEA)
+ return fgetea(filedes, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_FD)
+ char *s;
+ ssize_t retval;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+
+ if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) {
+ if(retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0)
+ return retval;
+ }
+
+ LOG(log_debug, logtype_default, "sys_fgetxattr: extattr_get_fd(): %s",
+ strerror(errno)));
+ return -1;
+#elif defined(HAVE_ATTR_GETF)
+ int retval, flags = 0;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags);
+
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
+{
+ const char *name = prefix(uname);
+
+#if defined(HAVE_LGETXATTR)
+ return lgetxattr(path, name, value, size);
+#elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
+ int options = XATTR_NOFOLLOW;
+ return getxattr(path, name, value, size, 0, options);
+#elif defined(HAVE_LGETEA)
+ return lgetea(path, name, value, size);
+#elif defined(HAVE_EXTATTR_GET_LINK)
+ ssize_t retval;
+ if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
+ if(retval > size) {
+ errno = ERANGE;
+ return -1;
+ }
+ if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
+ return retval;
+ }
+
+ LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
+ return -1;
+#elif defined(HAVE_ATTR_GET)
+ int retval, flags = ATTR_DONTFOLLOW;
+ int valuelength = (int)size;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
+
+ return retval ? retval : valuelength;
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+ if (attrfd >= 0) {
+ ret = solaris_read_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+#if defined(HAVE_EXTATTR_LIST_FILE)
+
+#define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
+
+static struct {
+ int space;
+ const char *name;
+ size_t len;
+}
+extattr[] = {
+ { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
+ { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
+};
+
+typedef union {
+ const char *path;
+ int filedes;
+} extattr_arg;
+
+static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
+{
+ ssize_t list_size;
+ int i, len;
+
+ switch(type) {
+#if defined(HAVE_EXTATTR_LIST_FILE)
+ case 0:
+ list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
+ break;
+#endif
+#if defined(HAVE_EXTATTR_LIST_LINK)
+ case 1:
+ list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
+ break;
+#endif
+#if defined(HAVE_EXTATTR_LIST_FD)
+ case 2:
+ list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
+ break;
+#endif
+ default:
+ errno = ENOSYS;
+ return -1;
+ }
+
+ /* Some error happend. Errno should be set by the previous call */
+ if(list_size < 0)
+ return -1;
+
+ /* No attributes */
+ if(list_size == 0)
+ return 0;
+
+ /* XXX: Call with an empty buffer may be used to calculate
+ necessary buffer size. Unfortunately, we can't say, how
+ many attributes were returned, so here is the potential
+ problem with the emulation.
+ */
+ if(list == NULL)
+ return list_size;
+
+ /* Buffer is too small to fit the results */
+ if(list_size > size) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ /* Convert from pascal strings to C strings */
+ len = list[0];
+ memmove(list, list + 1, list_size);
+
+ for(i = len; i < list_size; ) {
+ LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
+
+ len = list[i];
+ list[i] = '\0';
+ i += len + 1;
+ }
+
+ return list_size;
+}
+
+#endif
+
+#if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+static char attr_buffer[ATTR_MAX_VALUELEN];
+
+static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
+{
+ int retval = 0, index;
+ attrlist_cursor_t *cursor = 0;
+ int total_size = 0;
+ attrlist_t * al = (attrlist_t *)attr_buffer;
+ attrlist_ent_t *ae;
+ size_t ent_size, left = size;
+ char *bp = list;
+
+ while (True) {
+ if (filedes)
+ retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ else
+ retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ if (retval) break;
+ for (index = 0; index < al->al_count; index++) {
+ ae = ATTR_ENTRY(attr_buffer, index);
+ ent_size = strlen(ae->a_name) + sizeof("user.");
+ if (left >= ent_size) {
+ strncpy(bp, "user.", sizeof("user."));
+ strncat(bp, ae->a_name, ent_size - sizeof("user."));
+ bp += ent_size;
+ left -= ent_size;
+ } else if (size) {
+ errno = ERANGE;
+ retval = -1;
+ break;
+ }
+ total_size += ent_size;
+ }
+ if (al->al_more == 0) break;
+ }
+ if (retval == 0) {
+ flags |= ATTR_ROOT;
+ cursor = 0;
+ while (True) {
+ if (filedes)
+ retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ else
+ retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
+ if (retval) break;
+ for (index = 0; index < al->al_count; index++) {
+ ae = ATTR_ENTRY(attr_buffer, index);
+ ent_size = strlen(ae->a_name) + sizeof("system.");
+ if (left >= ent_size) {
+ strncpy(bp, "system.", sizeof("system."));
+ strncat(bp, ae->a_name, ent_size - sizeof("system."));
+ bp += ent_size;
+ left -= ent_size;
+ } else if (size) {
+ errno = ERANGE;
+ retval = -1;
+ break;
+ }
+ total_size += ent_size;
+ }
+ if (al->al_more == 0) break;
+ }
+ }
+ return (ssize_t)(retval ? retval : total_size);
+}
+
+#endif
+
+#if defined(HAVE_LISTXATTR)
+static ssize_t remove_user(ssize_t ret, char *list, size_t size)
+{
+ size_t len;
+ char *ptr;
+ char *ptr1;
+ ssize_t ptrsize;
+
+ if (ret <= 0 || size == 0)
+ return ret;
+ ptrsize = ret;
+ ptr = ptr1 = list;
+ while (ptrsize > 0) {
+ len = strlen(ptr1) +1;
+ ptrsize -= len;
+ if (strncmp(ptr1, "user.",5)) {
+ ptr1 += len;
+ continue;
+ }
+ memmove(ptr, ptr1 +5, len -5);
+ ptr += len -5;
+ ptr1 += len;
+ }
+ return ptr -list;
+}
+#endif
+
+ssize_t sys_listxattr (const char *path, char *list, size_t size)
+{
+#if defined(HAVE_LISTXATTR)
+ ssize_t ret;
+
+#ifndef XATTR_ADD_OPT
+ ret = listxattr(path, list, size);
+#else
+ int options = 0;
+ ret = listxattr(path, list, size, options);
+#endif
+ return remove_user(ret, list, size);
+
+#elif defined(HAVE_LISTEA)
+ return listea(path, list, size);
+#elif defined(HAVE_EXTATTR_LIST_FILE)
+ extattr_arg arg;
+ arg.path = path;
+ return bsd_attr_list(0, arg, list, size);
+#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+ return irix_attr_list(path, 0, list, size, 0);
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_list_xattr(attrdirfd, list, size);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+ssize_t sys_llistxattr (const char *path, char *list, size_t size)
+{
+#if defined(HAVE_LLISTXATTR)
+ ssize_t ret;
+
+ ret = llistxattr(path, list, size);
+ return remove_user(ret, list, size);
+#elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
+ ssize_t ret;
+ int options = XATTR_NOFOLLOW;
+
+ ret = listxattr(path, list, size, options);
+ return remove_user(ret, list, size);
+
+#elif defined(HAVE_LLISTEA)
+ return llistea(path, list, size);
+#elif defined(HAVE_EXTATTR_LIST_LINK)
+ extattr_arg arg;
+ arg.path = path;
+ return bsd_attr_list(1, arg, list, size);
+#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
+ return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
+#elif defined(HAVE_ATTROPEN)
+ ssize_t ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_list_xattr(attrdirfd, list, size);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_removexattr (const char *path, const char *uname)
+{
+ const char *name = prefix(uname);
+#if defined(HAVE_REMOVEXATTR)
+#ifndef XATTR_ADD_OPT
+ return removexattr(path, name);
+#else
+ int options = 0;
+ return removexattr(path, name, options);
+#endif
+#elif defined(HAVE_REMOVEEA)
+ return removeea(path, name);
+#elif defined(HAVE_EXTATTR_DELETE_FILE)
+ return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
+#elif defined(HAVE_ATTR_REMOVE)
+ int flags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_unlinkat(attrdirfd, name);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_lremovexattr (const char *path, const char *uname)
+{
+ const char *name = prefix(uname);
+#if defined(HAVE_LREMOVEXATTR)
+ return lremovexattr(path, name);
+#elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
+ int options = XATTR_NOFOLLOW;
+ return removexattr(path, name, options);
+#elif defined(HAVE_LREMOVEEA)
+ return lremoveea(path, name);
+#elif defined(HAVE_EXTATTR_DELETE_LINK)
+ return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
+#elif defined(HAVE_ATTR_REMOVE)
+ int flags = ATTR_DONTFOLLOW;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
+
+ return attr_remove(path, attrname, flags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
+ if (attrdirfd >= 0) {
+ ret = solaris_unlinkat(attrdirfd, name);
+ close(attrdirfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
+{
+ const char *name = prefix(uname);
+#if defined(HAVE_SETXATTR)
+#ifndef XATTR_ADD_OPT
+ return setxattr(path, name, value, size, flags);
+#else
+ int options = 0;
+ return setxattr(path, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_SETEA)
+ return setea(path, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_FILE)
+ int retval = 0;
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SET)
+ int myflags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ return attr_set(path, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int myflags = O_RDWR;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ ret = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_fsetxattr (int filedes, const char *uname, const void *value, size_t size, int flags)
+{
+ const char *name = prefix(uname);
+
+#if defined(HAVE_FSETXATTR)
+#ifndef XATTR_ADD_OPT
+ return fsetxattr(filedes, name, value, size, flags);
+#else
+ int options = 0;
+ return fsetxattr(filedes, name, value, size, 0, options);
+#endif
+#elif defined(HAVE_FSETEA)
+ return fsetea(filedes, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_FD)
+ char *s;
+ int retval = 0;
+ int attrnamespace = (strncmp(name, "system", 6) == 0) ?
+ EXTATTR_NAMESPACE_SYSTEM : EXTATTR_NAMESPACE_USER;
+ const char *attrname = ((s=strchr_m(name, '.')) == NULL) ? name : s + 1;
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ log_error, logtype_default /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+ retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SETF)
+ int myflags = 0;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ return attr_setf(filedes, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int myflags = O_RDWR | O_XATTR;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ ret = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
+{
+ const char *name = prefix(uname);
+#if defined(HAVE_LSETXATTR)
+ return lsetxattr(path, name, value, size, flags);
+#elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
+ int options = XATTR_NOFOLLOW;
+ return setxattr(path, name, value, size, 0, options);
+#elif defined(LSETEA)
+ return lsetea(path, name, value, size, flags);
+#elif defined(HAVE_EXTATTR_SET_LINK)
+ int retval = 0;
+ if (flags) {
+ /* Check attribute existence */
+ retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
+ if (retval < 0) {
+ /* REPLACE attribute, that doesn't exist */
+ if (flags & XATTR_REPLACE && errno == ENOATTR) {
+ errno = ENOATTR;
+ return -1;
+ }
+ /* Ignore other errors */
+ }
+ else {
+ /* CREATE attribute, that already exists */
+ if (flags & XATTR_CREATE) {
+ errno = EEXIST;
+ return -1;
+ }
+ }
+ }
+
+ retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
+ return (retval < 0) ? -1 : 0;
+#elif defined(HAVE_ATTR_SET)
+ int myflags = ATTR_DONTFOLLOW;
+ char *attrname = strchr(name,'.') + 1;
+
+ if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
+ if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
+ if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
+
+ return attr_set(path, attrname, (const char *)value, size, myflags);
+#elif defined(HAVE_ATTROPEN)
+ int ret = -1;
+ int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
+ int attrfd;
+ if (flags & XATTR_CREATE) myflags |= O_EXCL;
+ if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
+ attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
+ if (attrfd >= 0) {
+ ret = solaris_write_xattr(attrfd, value, size);
+ close(attrfd);
+ }
+ return ret;
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+/**************************************************************************
+ helper functions for Solaris' EA support
+****************************************************************************/
+#ifdef HAVE_ATTROPEN
+static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
+{
+ struct stat sbuf;
+
+ if (fstat(attrfd, &sbuf) == -1) {
+ return -1;
+ }
+
+ /* This is to return the current size of the named extended attribute */
+ if (size == 0) {
+ return sbuf.st_size;
+ }
+
+ /* check size and read xattr */
+ if (sbuf.st_size > size) {
+ return -1;
+ }
+
+ return read(attrfd, value, sbuf.st_size);
+}
+
+static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
+{
+ ssize_t len = 0;
+ DIR *dirp;
+ struct dirent *de;
+ int newfd = dup(attrdirfd);
+ /* CAUTION: The originating file descriptor should not be
+ used again following the call to fdopendir().
+ For that reason we dup() the file descriptor
+ here to make things more clear. */
+ dirp = fdopendir(newfd);
+
+ while ((de = readdir(dirp))) {
+ size_t listlen;
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
+ !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw"))
+ {
+ /* we don't want "." and ".." here: */
+ LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
+ continue;
+ }
+
+ listlen = strlen(de->d_name);
+ if (size == 0) {
+ /* return the current size of the list of extended attribute names*/
+ len += listlen + 1;
+ } else {
+ /* check size and copy entry + nul into list. */
+ if ((len + listlen + 1) > size) {
+ errno = ERANGE;
+ len = -1;
+ break;
+ } else {
+ strcpy(list + len, de->d_name);
+ len += listlen;
+ list[len] = '\0';
+ ++len;
+ }
+ }
+ }
+
+ if (closedir(dirp) == -1) {
+ LOG(log_debug, logtype_default, "closedir dirp failed: %s\n",strerror(errno));
+ return -1;
+ }
+ return len;
+}
+
+static int solaris_unlinkat(int attrdirfd, const char *name)
+{
+ if (unlinkat(attrdirfd, name, 0) == -1) {
+ return -1;
+ }
+ return 0;
+}
+
+static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
+{
+ int filedes = attropen(path, attrpath, oflag, mode);
+ if (filedes == -1) {
+ LOG(log_maxdebug, logtype_default, "attropen FAILED: path: %s, name: %s, errno: %s",
+ path, attrpath, strerror(errno));
+ errno = ENOATTR;
+ }
+ return filedes;
+}
+
+static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
+{
+ int filedes = openat(fildes, path, oflag, mode);
+ if (filedes == -1) {
+ LOG(log_maxdebug, logtype_default, "openat FAILED: fd: %d, path: %s, errno: %s",
+ filedes, path, strerror(errno));
+ }
+ return filedes;
+}
+
+static int solaris_write_xattr(int attrfd, const char *value, size_t size)
+{
+ if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
+ return 0;
+ } else {
+ LOG(log_maxdebug, logtype_default, "solaris_write_xattr FAILED!");
+ return -1;
+ }
+}
+
+#endif /*HAVE_ATTROPEN*/
+
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Samba system utilities
- Copyright (C) Andrew Tridgell 1992-1998
- Copyright (C) Jeremy Allison 1998-2005
- Copyright (C) Timur Bakeyev 2005
- Copyright (C) Bjoern Jacke 2006-2007
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- sys_copyxattr modified from LGPL2.1 libattr copyright
- Copyright (C) 2001-2002 Silicon Graphics, Inc. All Rights Reserved.
- Copyright (C) 2001 Andreas Gruenbacher.
-
- Samba 3.0.28, modified for netatalk.
- $Id: sys_ea.c,v 1.6 2009-12-04 10:26:10 franklahm Exp $
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <errno.h>
-
-#if HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#elif HAVE_SYS_XATTR_H
-#include <sys/xattr.h>
-#endif
-
-#ifdef HAVE_SYS_EA_H
-#include <sys/ea.h>
-#endif
-
-#ifdef HAVE_ATTROPEN
-
-#include <dirent.h>
-#endif
-
-#ifdef HAVE_SYS_EXTATTR_H
-#include <sys/extattr.h>
-#endif
-
-#include <atalk/adouble.h>
-#include <atalk/util.h>
-#include <atalk/logger.h>
-#include <atalk/ea.h>
-
-#ifndef ENOATTR
-#define ENOATTR ENODATA
-#endif
-
-/******** Solaris EA helper function prototypes ********/
-#ifdef HAVE_ATTROPEN
-#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP
-static int solaris_write_xattr(int attrfd, const char *value, size_t size);
-static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size);
-static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size);
-static int solaris_unlinkat(int attrdirfd, const char *name);
-static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode);
-static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode);
-#endif
-
-/**************************************************************************
- Wrappers for extented attribute calls. Based on the Linux package with
- support for IRIX and (Net|Free)BSD also. Expand as other systems have them.
-****************************************************************************/
-static char attr_name[256 +5] = "user.";
-
-static const char *prefix(const char *uname)
-{
-#if defined(HAVE_ATTROPEN)
- return uname;
-#else
- strlcpy(attr_name +5, uname, 256);
- return attr_name;
-#endif
-}
-
-ssize_t sys_getxattr (const char *path, const char *uname, void *value, size_t size)
-{
- const char *name = prefix(uname);
-
-#if defined(HAVE_GETXATTR)
-#ifndef XATTR_ADD_OPT
- return getxattr(path, name, value, size);
-#else
- int options = 0;
- return getxattr(path, name, value, size, 0, options);
-#endif
-#elif defined(HAVE_GETEA)
- return getea(path, name, value, size);
-#elif defined(HAVE_EXTATTR_GET_FILE)
- ssize_t retval;
- /*
- * The BSD implementation has a nasty habit of silently truncating
- * the returned value to the size of the buffer, so we have to check
- * that the buffer is large enough to fit the returned value.
- */
- if((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
- if (size == 0)
- /* size == 0 means only return size */
- return retval;
- if (retval > size) {
- errno = ERANGE;
- return -1;
- }
- if ((retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
- return retval;
- }
-
- LOG(log_maxdebug, logtype_default, "sys_getxattr: extattr_get_file() failed with: %s\n", strerror(errno));
- return -1;
-#elif defined(HAVE_ATTR_GET)
- int retval, flags = 0;
- int valuelength = (int)size;
- char *attrname = strchr(name,'.') + 1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
-
- return retval ? retval : valuelength;
-#elif defined(HAVE_ATTROPEN)
- ssize_t ret = -1;
- int attrfd = solaris_attropen(path, name, O_RDONLY, 0);
- if (attrfd >= 0) {
- ret = solaris_read_xattr(attrfd, value, size);
- close(attrfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-ssize_t sys_lgetxattr (const char *path, const char *uname, void *value, size_t size)
-{
- const char *name = prefix(uname);
-
-#if defined(HAVE_LGETXATTR)
- return lgetxattr(path, name, value, size);
-#elif defined(HAVE_GETXATTR) && defined(XATTR_ADD_OPT)
- int options = XATTR_NOFOLLOW;
- return getxattr(path, name, value, size, 0, options);
-#elif defined(HAVE_LGETEA)
- return lgetea(path, name, value, size);
-#elif defined(HAVE_EXTATTR_GET_LINK)
- ssize_t retval;
- if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0)) >= 0) {
- if(retval > size) {
- errno = ERANGE;
- return -1;
- }
- if((retval=extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, value, size)) >= 0)
- return retval;
- }
-
- LOG(log_maxdebug, logtype_default, "sys_lgetxattr: extattr_get_link() failed with: %s\n", strerror(errno));
- return -1;
-#elif defined(HAVE_ATTR_GET)
- int retval, flags = ATTR_DONTFOLLOW;
- int valuelength = (int)size;
- char *attrname = strchr(name,'.') + 1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- retval = attr_get(path, attrname, (char *)value, &valuelength, flags);
-
- return retval ? retval : valuelength;
-#elif defined(HAVE_ATTROPEN)
- ssize_t ret = -1;
- int attrfd = solaris_attropen(path, name, O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
- if (attrfd >= 0) {
- ret = solaris_read_xattr(attrfd, value, size);
- close(attrfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-#if defined(HAVE_EXTATTR_LIST_FILE)
-
-#define EXTATTR_PREFIX(s) (s), (sizeof((s))-1)
-
-static struct {
- int space;
- const char *name;
- size_t len;
-}
-extattr[] = {
- { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("") },
- { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("") },
-};
-
-typedef union {
- const char *path;
- int filedes;
-} extattr_arg;
-
-static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size)
-{
- ssize_t list_size;
- int i, len;
-
- switch(type) {
-#if defined(HAVE_EXTATTR_LIST_FILE)
- case 0:
- list_size = extattr_list_file(arg.path, EXTATTR_NAMESPACE_USER, list, size);
- break;
-#endif
-#if defined(HAVE_EXTATTR_LIST_LINK)
- case 1:
- list_size = extattr_list_link(arg.path, EXTATTR_NAMESPACE_USER, list, size);
- break;
-#endif
-#if defined(HAVE_EXTATTR_LIST_FD)
- case 2:
- list_size = extattr_list_fd(arg.filedes, EXTATTR_NAMESPACE_USER, list, size);
- break;
-#endif
- default:
- errno = ENOSYS;
- return -1;
- }
-
- /* Some error happend. Errno should be set by the previous call */
- if(list_size < 0)
- return -1;
-
- /* No attributes */
- if(list_size == 0)
- return 0;
-
- /* XXX: Call with an empty buffer may be used to calculate
- necessary buffer size. Unfortunately, we can't say, how
- many attributes were returned, so here is the potential
- problem with the emulation.
- */
- if(list == NULL)
- return list_size;
-
- /* Buffer is too small to fit the results */
- if(list_size > size) {
- errno = ERANGE;
- return -1;
- }
-
- /* Convert from pascal strings to C strings */
- len = list[0];
- memmove(list, list + 1, list_size);
-
- for(i = len; i < list_size; ) {
- LOG(log_maxdebug, logtype_afpd, "len: %d, i: %d", len, i);
-
- len = list[i];
- list[i] = '\0';
- i += len + 1;
- }
-
- return list_size;
-}
-
-#endif
-
-#if defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
-static char attr_buffer[ATTR_MAX_VALUELEN];
-
-static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags)
-{
- int retval = 0, index;
- attrlist_cursor_t *cursor = 0;
- int total_size = 0;
- attrlist_t * al = (attrlist_t *)attr_buffer;
- attrlist_ent_t *ae;
- size_t ent_size, left = size;
- char *bp = list;
-
- while (True) {
- if (filedes)
- retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- else
- retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- if (retval) break;
- for (index = 0; index < al->al_count; index++) {
- ae = ATTR_ENTRY(attr_buffer, index);
- ent_size = strlen(ae->a_name) + sizeof("user.");
- if (left >= ent_size) {
- strncpy(bp, "user.", sizeof("user."));
- strncat(bp, ae->a_name, ent_size - sizeof("user."));
- bp += ent_size;
- left -= ent_size;
- } else if (size) {
- errno = ERANGE;
- retval = -1;
- break;
- }
- total_size += ent_size;
- }
- if (al->al_more == 0) break;
- }
- if (retval == 0) {
- flags |= ATTR_ROOT;
- cursor = 0;
- while (True) {
- if (filedes)
- retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- else
- retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor);
- if (retval) break;
- for (index = 0; index < al->al_count; index++) {
- ae = ATTR_ENTRY(attr_buffer, index);
- ent_size = strlen(ae->a_name) + sizeof("system.");
- if (left >= ent_size) {
- strncpy(bp, "system.", sizeof("system."));
- strncat(bp, ae->a_name, ent_size - sizeof("system."));
- bp += ent_size;
- left -= ent_size;
- } else if (size) {
- errno = ERANGE;
- retval = -1;
- break;
- }
- total_size += ent_size;
- }
- if (al->al_more == 0) break;
- }
- }
- return (ssize_t)(retval ? retval : total_size);
-}
-
-#endif
-
-#if defined(HAVE_LISTXATTR)
-static ssize_t remove_user(ssize_t ret, char *list, size_t size)
-{
- size_t len;
- char *ptr;
- char *ptr1;
- ssize_t ptrsize;
-
- if (ret <= 0 || size == 0)
- return ret;
- ptrsize = ret;
- ptr = ptr1 = list;
- while (ptrsize > 0) {
- len = strlen(ptr1) +1;
- ptrsize -= len;
- if (strncmp(ptr1, "user.",5)) {
- ptr1 += len;
- continue;
- }
- memmove(ptr, ptr1 +5, len -5);
- ptr += len -5;
- ptr1 += len;
- }
- return ptr -list;
-}
-#endif
-
-ssize_t sys_listxattr (const char *path, char *list, size_t size)
-{
-#if defined(HAVE_LISTXATTR)
- ssize_t ret;
-
-#ifndef XATTR_ADD_OPT
- ret = listxattr(path, list, size);
-#else
- int options = 0;
- ret = listxattr(path, list, size, options);
-#endif
- return remove_user(ret, list, size);
-
-#elif defined(HAVE_LISTEA)
- return listea(path, list, size);
-#elif defined(HAVE_EXTATTR_LIST_FILE)
- extattr_arg arg;
- arg.path = path;
- return bsd_attr_list(0, arg, list, size);
-#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
- return irix_attr_list(path, 0, list, size, 0);
-#elif defined(HAVE_ATTROPEN)
- ssize_t ret = -1;
- int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
- if (attrdirfd >= 0) {
- ret = solaris_list_xattr(attrdirfd, list, size);
- close(attrdirfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-ssize_t sys_llistxattr (const char *path, char *list, size_t size)
-{
-#if defined(HAVE_LLISTXATTR)
- ssize_t ret;
-
- ret = llistxattr(path, list, size);
- return remove_user(ret, list, size);
-#elif defined(HAVE_LISTXATTR) && defined(XATTR_ADD_OPT)
- ssize_t ret;
- int options = XATTR_NOFOLLOW;
-
- ret = listxattr(path, list, size, options);
- return remove_user(ret, list, size);
-
-#elif defined(HAVE_LLISTEA)
- return llistea(path, list, size);
-#elif defined(HAVE_EXTATTR_LIST_LINK)
- extattr_arg arg;
- arg.path = path;
- return bsd_attr_list(1, arg, list, size);
-#elif defined(HAVE_ATTR_LIST) && defined(HAVE_SYS_ATTRIBUTES_H)
- return irix_attr_list(path, 0, list, size, ATTR_DONTFOLLOW);
-#elif defined(HAVE_ATTROPEN)
- ssize_t ret = -1;
- int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
- if (attrdirfd >= 0) {
- ret = solaris_list_xattr(attrdirfd, list, size);
- close(attrdirfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_removexattr (const char *path, const char *uname)
-{
- const char *name = prefix(uname);
-#if defined(HAVE_REMOVEXATTR)
-#ifndef XATTR_ADD_OPT
- return removexattr(path, name);
-#else
- int options = 0;
- return removexattr(path, name, options);
-#endif
-#elif defined(HAVE_REMOVEEA)
- return removeea(path, name);
-#elif defined(HAVE_EXTATTR_DELETE_FILE)
- return extattr_delete_file(path, EXTATTR_NAMESPACE_USER, uname);
-#elif defined(HAVE_ATTR_REMOVE)
- int flags = 0;
- char *attrname = strchr(name,'.') + 1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- return attr_remove(path, attrname, flags);
-#elif defined(HAVE_ATTROPEN)
- int ret = -1;
- int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0);
- if (attrdirfd >= 0) {
- ret = solaris_unlinkat(attrdirfd, name);
- close(attrdirfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_lremovexattr (const char *path, const char *uname)
-{
- const char *name = prefix(uname);
-#if defined(HAVE_LREMOVEXATTR)
- return lremovexattr(path, name);
-#elif defined(HAVE_REMOVEXATTR) && defined(XATTR_ADD_OPT)
- int options = XATTR_NOFOLLOW;
- return removexattr(path, name, options);
-#elif defined(HAVE_LREMOVEEA)
- return lremoveea(path, name);
-#elif defined(HAVE_EXTATTR_DELETE_LINK)
- return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, uname);
-#elif defined(HAVE_ATTR_REMOVE)
- int flags = ATTR_DONTFOLLOW;
- char *attrname = strchr(name,'.') + 1;
-
- if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT;
-
- return attr_remove(path, attrname, flags);
-#elif defined(HAVE_ATTROPEN)
- int ret = -1;
- int attrdirfd = solaris_attropen(path, ".", O_RDONLY|AT_SYMLINK_NOFOLLOW, 0);
- if (attrdirfd >= 0) {
- ret = solaris_unlinkat(attrdirfd, name);
- close(attrdirfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_setxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
-{
- const char *name = prefix(uname);
-#if defined(HAVE_SETXATTR)
-#ifndef XATTR_ADD_OPT
- return setxattr(path, name, value, size, flags);
-#else
- int options = 0;
- return setxattr(path, name, value, size, 0, options);
-#endif
-#elif defined(HAVE_SETEA)
- return setea(path, name, value, size, flags);
-#elif defined(HAVE_EXTATTR_SET_FILE)
- int retval = 0;
- if (flags) {
- /* Check attribute existence */
- retval = extattr_get_file(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
- if (retval < 0) {
- /* REPLACE attribute, that doesn't exist */
- if (flags & XATTR_REPLACE && errno == ENOATTR) {
- errno = ENOATTR;
- return -1;
- }
- /* Ignore other errors */
- }
- else {
- /* CREATE attribute, that already exists */
- if (flags & XATTR_CREATE) {
- errno = EEXIST;
- return -1;
- }
- }
- }
- retval = extattr_set_file(path, EXTATTR_NAMESPACE_USER, uname, value, size);
- return (retval < 0) ? -1 : 0;
-#elif defined(HAVE_ATTR_SET)
- int myflags = 0;
- char *attrname = strchr(name,'.') + 1;
-
- if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
- if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
- if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
-
- return attr_set(path, attrname, (const char *)value, size, myflags);
-#elif defined(HAVE_ATTROPEN)
- int ret = -1;
- int myflags = O_RDWR;
- int attrfd;
- if (flags & XATTR_CREATE) myflags |= O_EXCL;
- if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
- attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
- if (attrfd >= 0) {
- ret = solaris_write_xattr(attrfd, value, size);
- close(attrfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-int sys_lsetxattr (const char *path, const char *uname, const void *value, size_t size, int flags)
-{
- const char *name = prefix(uname);
-#if defined(HAVE_LSETXATTR)
- return lsetxattr(path, name, value, size, flags);
-#elif defined(HAVE_SETXATTR) && defined(XATTR_ADD_OPT)
- int options = XATTR_NOFOLLOW;
- return setxattr(path, name, value, size, 0, options);
-#elif defined(LSETEA)
- return lsetea(path, name, value, size, flags);
-#elif defined(HAVE_EXTATTR_SET_LINK)
- int retval = 0;
- if (flags) {
- /* Check attribute existence */
- retval = extattr_get_link(path, EXTATTR_NAMESPACE_USER, uname, NULL, 0);
- if (retval < 0) {
- /* REPLACE attribute, that doesn't exist */
- if (flags & XATTR_REPLACE && errno == ENOATTR) {
- errno = ENOATTR;
- return -1;
- }
- /* Ignore other errors */
- }
- else {
- /* CREATE attribute, that already exists */
- if (flags & XATTR_CREATE) {
- errno = EEXIST;
- return -1;
- }
- }
- }
-
- retval = extattr_set_link(path, EXTATTR_NAMESPACE_USER, uname, value, size);
- return (retval < 0) ? -1 : 0;
-#elif defined(HAVE_ATTR_SET)
- int myflags = ATTR_DONTFOLLOW;
- char *attrname = strchr(name,'.') + 1;
-
- if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT;
- if (flags & XATTR_CREATE) myflags |= ATTR_CREATE;
- if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE;
-
- return attr_set(path, attrname, (const char *)value, size, myflags);
-#elif defined(HAVE_ATTROPEN)
- int ret = -1;
- int myflags = O_RDWR | AT_SYMLINK_NOFOLLOW;
- int attrfd;
- if (flags & XATTR_CREATE) myflags |= O_EXCL;
- if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT;
- attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE);
- if (attrfd >= 0) {
- ret = solaris_write_xattr(attrfd, value, size);
- close(attrfd);
- }
- return ret;
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-/**************************************************************************
- helper functions for Solaris' EA support
-****************************************************************************/
-#ifdef HAVE_ATTROPEN
-static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size)
-{
- struct stat sbuf;
-
- if (fstat(attrfd, &sbuf) == -1) {
- return -1;
- }
-
- /* This is to return the current size of the named extended attribute */
- if (size == 0) {
- return sbuf.st_size;
- }
-
- /* check size and read xattr */
- if (sbuf.st_size > size) {
- return -1;
- }
-
- return read(attrfd, value, sbuf.st_size);
-}
-
-static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size)
-{
- ssize_t len = 0;
- DIR *dirp;
- struct dirent *de;
- int newfd = dup(attrdirfd);
- /* CAUTION: The originating file descriptor should not be
- used again following the call to fdopendir().
- For that reason we dup() the file descriptor
- here to make things more clear. */
- dirp = fdopendir(newfd);
-
- while ((de = readdir(dirp))) {
- size_t listlen;
- if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ||
- !strcmp(de->d_name, "SUNWattr_ro") || !strcmp(de->d_name, "SUNWattr_rw"))
- {
- /* we don't want "." and ".." here: */
- LOG(log_maxdebug, logtype_default, "skipped EA %s\n",de->d_name);
- continue;
- }
-
- listlen = strlen(de->d_name);
- if (size == 0) {
- /* return the current size of the list of extended attribute names*/
- len += listlen + 1;
- } else {
- /* check size and copy entry + nul into list. */
- if ((len + listlen + 1) > size) {
- errno = ERANGE;
- len = -1;
- break;
- } else {
- strcpy(list + len, de->d_name);
- len += listlen;
- list[len] = '\0';
- ++len;
- }
- }
- }
-
- if (closedir(dirp) == -1) {
- LOG(log_debug, logtype_default, "closedir dirp failed: %s\n",strerror(errno));
- return -1;
- }
- return len;
-}
-
-static int solaris_unlinkat(int attrdirfd, const char *name)
-{
- if (unlinkat(attrdirfd, name, 0) == -1) {
- return -1;
- }
- return 0;
-}
-
-static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode)
-{
- int filedes = attropen(path, attrpath, oflag, mode);
- if (filedes == -1) {
- LOG(log_maxdebug, logtype_default, "attropen FAILED: path: %s, name: %s, errno: %s\n",path,attrpath,strerror(errno));
- errno = ENOATTR;
- }
- return filedes;
-}
-
-static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode)
-{
- int filedes = openat(fildes, path, oflag, mode);
- if (filedes == -1) {
- LOG(log_maxdebug, logtype_default, "openat FAILED: fd: %s, path: %s, errno: %s\n",filedes,path,strerror(errno));
- }
- return filedes;
-}
-
-static int solaris_write_xattr(int attrfd, const char *value, size_t size)
-{
- if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) {
- return 0;
- } else {
- LOG(log_maxdebug, logtype_default, "solaris_write_xattr FAILED!\n");
- return -1;
- }
-}
-
-#endif /*HAVE_ATTROPEN*/
-
static int RF_chown_adouble(VFS_FUNC_ARGS_CHOWN)
{
struct stat st;
- char *ad_p;
+ const char *ad_p;
ad_p = vol->ad_path(path, ADFLAGS_HF );
/* ----------------- */
static int RF_setdirunixmode_adouble(VFS_FUNC_ARGS_SETDIRUNIXMODE)
{
- char *adouble = vol->ad_path(name, ADFLAGS_DIR );
+ const char *adouble = vol->ad_path(name, ADFLAGS_DIR );
int dropbox = vol->v_flags;
if (dir_rx_set(mode)) {
{
int dropbox = vol->v_flags;
mode_t hf_mode = ad_hf_mode(mode);
- char *adouble = vol->ad_path(name, ADFLAGS_DIR );
- char *adouble_p = ad_dir(adouble);
+ const char *adouble = vol->ad_path(name, ADFLAGS_DIR );
+ const char *adouble_p = ad_dir(adouble);
if (dir_rx_set(mode)) {
if (stickydirmode(ad_dir(adouble), DIRBITS | mode, dropbox, vol->v_umask) < 0)
* use a diff one, it's not a pb,ie it's not the same file, yet.
*/
ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
+ if (ad_open(&ad, dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666) == 0) {
ad_close(&ad, ADFLAGS_HF);
if (!unix_rename(dirfd, adsrc, -1, vol->ad_path(dst, 0 )) )
err = 0;
}
#endif
-/*********************************************************************************
- * sfm adouble format
- *********************************************************************************/
-static int ads_chown_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
-{
- struct perm *owner = data;
-
- if (chown( name , owner->uid, owner->gid ) < 0) {
- return -1;
- }
- return 0;
-}
-
-static int RF_chown_ads(VFS_FUNC_ARGS_CHOWN)
-{
- struct stat st;
- char *ad_p;
- struct perm owner;
-
- owner.uid = uid;
- owner.gid = gid;
-
-
- ad_p = ad_dir(vol->ad_path(path, ADFLAGS_HF ));
-
- if ( stat( ad_p, &st ) < 0 ) {
- /* ignore */
- return 0;
- }
-
- if (chown( ad_p, uid, gid ) < 0) {
- return -1;
- }
- return for_each_adouble("chown_ads", ad_p, ads_chown_loop, &owner, 1, vol->v_umask);
-}
-
-/* --------------------------------- */
-static int deletecurdir_ads1_loop(struct dirent *de _U_, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
-{
- return netatalk_unlink(name);
-}
-
-static int ads_delete_rf(char *name)
-{
- int err;
-
- if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0)))
- return err;
- /* FIXME
- * it's a problem for a nfs mounted folder, there's .nfsxxx around
- * for linux the following line solve it.
- * but it could fail if rm .nfsxxx create a new .nfsyyy :(
- */
- if ((err = for_each_adouble("deletecurdir", name, deletecurdir_ads1_loop, NULL, 1, 0)))
- return err;
- return netatalk_rmdir(-1, name);
-}
-
-static int deletecurdir_ads_loop(struct dirent *de, char *name, void *data _U_, int flag _U_, mode_t v_umask _U_)
-{
- struct stat st;
-
- /* bail if the file exists in the current directory.
- * note: this will not fail with dangling symlinks */
-
- if (stat(de->d_name, &st) == 0) {
- return AFPERR_DIRNEMPT;
- }
- return ads_delete_rf(name);
-}
-
-static int RF_deletecurdir_ads(VFS_FUNC_ARGS_DELETECURDIR)
-{
- int err;
-
- /* delete stray .AppleDouble files. this happens to get .Parent files as well. */
- if ((err = for_each_adouble("deletecurdir", ".AppleDouble", deletecurdir_ads_loop, NULL, 1, 0)))
- return err;
-
- return netatalk_rmdir(-1, ".AppleDouble" );
-}
-
-/* ------------------- */
-struct set_mode {
- mode_t mode;
- struct stat *st;
-};
-
-static int ads_setfilmode_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask)
+/*************************************************************************
+ * EA adouble format
+ ************************************************************************/
+static int validupath_ea(VFS_FUNC_ARGS_VALIDUPATH)
{
- struct set_mode *param = data;
-
- return setfilmode(name, param->mode, param->st, v_umask);
-}
+ return 1;
+}
-static int ads_setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask)
+/* ----------------- */
+static int RF_chown_ea(VFS_FUNC_ARGS_CHOWN)
{
- mode_t file_mode = ad_hf_mode(mode);
- mode_t dir_mode = file_mode;
- struct set_mode param;
-
- if ((dir_mode & (S_IRUSR | S_IWUSR )))
- dir_mode |= S_IXUSR;
- if ((dir_mode & (S_IRGRP | S_IWGRP )))
- dir_mode |= S_IXGRP;
- if ((dir_mode & (S_IROTH | S_IWOTH )))
- dir_mode |= S_IXOTH;
-
- /* change folder */
- dir_mode |= DIRBITS;
- if (dir_rx_set(dir_mode)) {
- if (chmod( name, dir_mode ) < 0)
- return -1;
- }
- param.st = st;
- param.mode = file_mode;
- if (for_each_adouble("setfilmode_ads", name, ads_setfilmode_loop, ¶m, 0, v_umask) < 0)
- return -1;
-
- if (!dir_rx_set(dir_mode)) {
- if (chmod( name, dir_mode ) < 0)
- return -1;
- }
-
return 0;
}
-static int RF_setfilmode_ads(VFS_FUNC_ARGS_SETFILEMODE)
+/* ---------------- */
+static int RF_renamedir_ea(VFS_FUNC_ARGS_RENAMEDIR)
{
- return ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_HF )), mode, st, vol->v_umask);
+ return 0;
}
-/* ------------------- */
-static int RF_setdirunixmode_ads(VFS_FUNC_ARGS_SETDIRUNIXMODE)
+/* ---------------- */
+static int RF_deletecurdir_ea(VFS_FUNC_ARGS_DELETECURDIR)
{
- char *adouble = vol->ad_path(name, ADFLAGS_DIR );
- char ad_p[ MAXPATHLEN + 1];
- int dropbox = vol->v_flags;
-
- strlcpy(ad_p,ad_dir(adouble), MAXPATHLEN + 1);
-
- if (dir_rx_set(mode)) {
-
- /* .AppleDouble */
- if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox, vol->v_umask) < 0)
- return -1;
-
- /* .AppleDouble/.Parent */
- if (stickydirmode(ad_p, DIRBITS | mode, dropbox, vol->v_umask) < 0)
- return -1;
- }
-
- if (ads_setfilmode(ad_dir(vol->ad_path(name, ADFLAGS_DIR)), mode, st, vol->v_umask) < 0)
- return -1;
-
- if (!dir_rx_set(mode)) {
- if (stickydirmode(ad_p, DIRBITS | mode, dropbox, vol->v_umask) < 0)
- return -1 ;
- if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, dropbox, vol->v_umask) < 0)
- return -1;
- }
return 0;
}
-/* ------------------- */
-struct dir_mode {
- mode_t mode;
- int dropbox;
-};
-
-static int setdirmode_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask)
+/* ---------------- */
+static int RF_setdirunixmode_ea(VFS_FUNC_ARGS_SETDIRUNIXMODE)
{
-
- struct dir_mode *param = data;
- int ret = 0; /* 0 ignore error, -1 */
-
- if (dir_rx_set(param->mode)) {
- if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) {
- if (flag) {
- return 0;
- }
- return ret;
- }
- }
- if (ads_setfilmode(name, param->mode, NULL, v_umask) < 0)
- return ret;
-
- if (!dir_rx_set(param->mode)) {
- if (stickydirmode(name, DIRBITS | param->mode, param->dropbox, v_umask) < 0) {
- if (flag) {
- return 0;
- }
- return ret;
- }
- }
return 0;
}
-static int RF_setdirmode_ads(VFS_FUNC_ARGS_SETDIRMODE)
+static int RF_setfilmode_ea(VFS_FUNC_ARGS_SETFILEMODE)
{
- char *adouble = vol->ad_path(name, ADFLAGS_DIR );
- char ad_p[ MAXPATHLEN + 1];
- struct dir_mode param;
-
- param.mode = mode;
- param.dropbox = vol->v_flags;
-
- strlcpy(ad_p,ad_dir(adouble), sizeof(ad_p));
-
- if (dir_rx_set(mode)) {
- /* .AppleDouble */
- if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox, vol->v_umask) < 0)
- return -1;
- }
-
- if (for_each_adouble("setdirmode_ads", ad_dir(ad_p), setdirmode_ads_loop, ¶m, vol_noadouble(vol), vol->v_umask))
- return -1;
-
- if (!dir_rx_set(mode)) {
- if (stickydirmode(ad_dir(ad_p), DIRBITS | mode, param.dropbox, vol->v_umask) < 0 )
- return -1;
- }
return 0;
}
-/* ------------------- */
-static int setdirowner_ads1_loop(struct dirent *de _U_, char *name, void *data, int flag _U_, mode_t v_umask _U_)
+/* ---------------- */
+static int RF_setdirmode_ea(VFS_FUNC_ARGS_SETDIRMODE)
{
- struct perm *owner = data;
-
- if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
- LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
- owner->uid, owner->gid, fullpathname(name), strerror(errno) );
- /* return ( -1 ); Sometimes this is okay */
- }
return 0;
}
-static int setdirowner_ads_loop(struct dirent *de _U_, char *name, void *data, int flag, mode_t v_umask _U_)
+/* ---------------- */
+static int RF_setdirowner_ea(VFS_FUNC_ARGS_SETDIROWNER)
{
- struct perm *owner = data;
-
- if (for_each_adouble("setdirowner", name, setdirowner_ads1_loop, data, flag, 0) < 0)
- return -1;
-
- if ( chown( name, owner->uid, owner->gid ) < 0 && errno != EPERM ) {
- LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
- owner->uid, owner->gid, fullpathname(name), strerror(errno) );
- /* return ( -1 ); Sometimes this is okay */
- }
- return 0;
+ return 0;
}
-static int RF_setdirowner_ads(VFS_FUNC_ARGS_SETDIROWNER)
+static int RF_deletefile_ea(VFS_FUNC_ARGS_DELETEFILE)
{
- int noadouble = vol_noadouble(vol);
- char adouble_p[ MAXPATHLEN + 1];
- struct stat st;
- struct perm owner;
-
- owner.uid = uid;
- owner.gid = gid;
-
- strlcpy(adouble_p, ad_dir(vol->ad_path(name, ADFLAGS_DIR )), sizeof(adouble_p));
-
- if (for_each_adouble("setdirowner", ad_dir(adouble_p), setdirowner_ads_loop, &owner, noadouble, 0))
- return -1;
-
- /*
- * We cheat: we know that chown doesn't do anything.
- */
- if ( stat( ".AppleDouble", &st ) < 0) {
- if (errno == ENOENT && noadouble)
- return 0;
- LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(".AppleDouble"), strerror(errno) );
- return -1;
- }
- if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 && errno != EPERM ) {
- LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
- uid, gid,fullpathname(".AppleDouble"), strerror(errno) );
- /* return ( -1 ); Sometimes this is okay */
- }
return 0;
}
-
-/* ------------------- */
-static int RF_deletefile_ads(VFS_FUNC_ARGS_DELETEFILE)
+static int RF_copyfile_ea(VFS_FUNC_ARGS_COPYFILE)
{
- int ret = 0;
- int cwd = -1;
- char *ad_p;
-
- ad_p = ad_dir(vol->ad_path(file, ADFLAGS_HF ));
-
- if (dirfd != -1) {
- if (((cwd = open(".", O_RDONLY)) == -1) || (fchdir(dirfd) != 0)) {
- ret = AFPERR_MISC;
- goto exit;
- }
- }
-
- ret = ads_delete_rf(ad_p);
-
- if (dirfd != -1 && fchdir(cwd) != 0) {
- LOG(log_error, logtype_afpd, "RF_deletefile_ads: cant chdir back. exit!");
- exit(EXITERR_SYS);
- }
-
-exit:
- if (cwd != -1)
- close(cwd);
-
- return ret;
+ return 0;
}
-/* --------------------------- */
-static int RF_renamefile_ads(VFS_FUNC_ARGS_RENAMEFILE)
+/* ---------------- */
+static int RF_renamefile_ea(VFS_FUNC_ARGS_RENAMEFILE)
{
- char adsrc[ MAXPATHLEN + 1];
- int err = 0;
-
- strcpy( adsrc, ad_dir(vol->ad_path(src, 0 )));
- if (unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) < 0) {
- struct stat st;
-
- err = errno;
- if (errno == ENOENT) {
- struct adouble ad;
-
- if (lstatat(dirfd, adsrc, &st)) /* source has no ressource fork, */
- return 0;
-
- /* We are here because :
- * -there's no dest folder.
- * -there's no .AppleDouble in the dest folder.
- * if we use the struct adouble passed in parameter it will not
- * create .AppleDouble if the file is already opened, so we
- * use a diff one, it's not a pb,ie it's not the same file, yet.
- */
- ad_init(&ad, vol->v_adouble, vol->v_ad_options);
- if (!ad_open(dst, ADFLAGS_HF, O_RDWR | O_CREAT, 0666, &ad)) {
- ad_close(&ad, ADFLAGS_HF);
-
- /* We must delete it */
- RF_deletefile_ads(vol, -1, dst );
- if (!unix_rename(dirfd, adsrc, -1, ad_dir(vol->ad_path(dst, 0 ))) )
- err = 0;
- else
- err = errno;
- }
- else { /* it's something else, bail out */
- err = errno;
- }
- }
- }
- if (err) {
- errno = err;
- return -1;
- }
- return 0;
+ return 0;
}
+#if 0
/*************************************************************************
* osx adouble format
************************************************************************/
}
return 0;
}
+#endif
/********************************************************************************************
* VFS chaining
};
/*
- * Primary adouble modules: default, osx, sfm
+ * Primary adouble modules: v2, ea
*/
-static struct vfs_ops netatalk_adouble = {
+static struct vfs_ops netatalk_adouble_v2 = {
/* vfs_validupath: */ validupath_adouble,
/* vfs_chown: */ RF_chown_adouble,
/* vfs_renamedir: */ RF_renamedir_adouble,
NULL
};
-static struct vfs_ops netatalk_adouble_osx = {
- /* vfs_validupath: */ validupath_osx,
- /* vfs_chown: */ RF_chown_adouble,
- /* vfs_renamedir: */ RF_renamedir_osx,
- /* vfs_deletecurdir: */ RF_deletecurdir_osx,
- /* vfs_setfilmode: */ RF_setfilmode_adouble,
- /* vfs_setdirmode: */ RF_setdirmode_osx,
- /* vfs_setdirunixmode:*/ RF_setdirunixmode_osx,
- /* vfs_setdirowner: */ RF_setdirowner_osx,
- /* vfs_deletefile: */ RF_deletefile_adouble,
- /* vfs_renamefile: */ RF_renamefile_osx,
- /* vfs_copyfile: */ NULL,
- NULL
-};
-
-/* samba sfm format. ad_path shouldn't be set her */
-static struct vfs_ops netatalk_adouble_sfm = {
- /* vfs_validupath: */ validupath_adouble,
- /* vfs_chown: */ RF_chown_ads,
- /* vfs_renamedir: */ RF_renamedir_adouble,
- /* vfs_deletecurdir: */ RF_deletecurdir_ads,
- /* vfs_setfilmode: */ RF_setfilmode_ads,
- /* vfs_setdirmode: */ RF_setdirmode_ads,
- /* vfs_setdirunixmode:*/ RF_setdirunixmode_ads,
- /* vfs_setdirowner: */ RF_setdirowner_ads,
- /* vfs_deletefile: */ RF_deletefile_ads,
- /* vfs_renamefile: */ RF_renamefile_ads,
- /* vfs_copyfile: */ NULL,
+static struct vfs_ops netatalk_adouble_ea = {
+ /* vfs_validupath: */ validupath_ea,
+ /* vfs_chown: */ RF_chown_ea,
+ /* vfs_renamedir: */ RF_renamedir_ea,
+ /* vfs_deletecurdir: */ RF_deletecurdir_ea,
+ /* vfs_setfilmode: */ RF_setfilmode_ea,
+ /* vfs_setdirmode: */ RF_setdirmode_ea,
+ /* vfs_setdirunixmode:*/ RF_setdirunixmode_ea,
+ /* vfs_setdirowner: */ RF_setdirowner_ea,
+ /* vfs_deletefile: */ RF_deletefile_ea,
+ /* vfs_renamefile: */ RF_renamefile_ea,
+ /* vfs_copyfile: */ RF_copyfile_ea,
NULL
};
vol->vfs = &vfs_master_funcs;
/* Default adouble stuff */
- if (vol->v_adouble == AD_VERSION2_OSX) {
- vol->vfs_modules[0] = &netatalk_adouble_osx;
- vol->ad_path = ad_path_osx;
- }
- else if (vol->v_adouble == AD_VERSION1_SFM) {
- vol->vfs_modules[0] = &netatalk_adouble_sfm;
- vol->ad_path = ad_path_sfm;
- }
- else {
- vol->vfs_modules[0] = &netatalk_adouble;
+ if (vol->v_adouble == AD_VERSION2) {
+ vol->vfs_modules[0] = &netatalk_adouble_v2;
vol->ad_path = ad_path;
+ } else {
+ vol->vfs_modules[0] = &netatalk_adouble_ea;
+ vol->ad_path = ad_path_ea;
}
/* Extended Attributes */
GENERATED_MANS = uniconv.1 asip-status.pl.1
TEMPLATE_FILES = uniconv.1.tmpl asip-status.pl.1.tmpl
+
NONGENERATED_MANS = ad.1 \
afppasswd.1 \
apple_dump.1 \
dbd.1 \
- hqx2bin.1 \
- macbinary.1 \
- megatron.1 \
- netatalk-config.1 \
- single2bin.1 \
- unbin.1 \
- unhex.1 \
- unsingle.1
+ netatalk-config.1
+
ATALK_MANS = aecho.1 \
getzones.1 \
nbp.1 \
#include <sys/types.h>
#include <netinet/in.h> /* so that we can deal with sun's s_net #define */
-#ifdef MACOSX_SERVER
+#if defined(MACOSX_SERVER) && (!defined(NO_DDP))
#include <netat/appletalk.h>
#endif /* MACOSX_SERVER */