/*
- * $Id: file.c,v 1.141 2010/03/12 15:16:49 franklahm Exp $
- *
* Copyright (c) 1990,1993 Regents of The University of Michigan.
* All Rights Reserved. See COPYRIGHT.
*/
#include <stdio.h>
#include <stdlib.h>
-/* STDC check */
-#if STDC_HEADERS
#include <string.h>
-#else /* STDC_HEADERS */
-#ifndef HAVE_STRCHR
-#define strchr index
-#define strrchr index
-#endif /* HAVE_STRCHR */
-char *strchr (), *strrchr ();
-
-#ifndef HAVE_MEMCPY
-#define memcpy(d,s,n) bcopy ((s), (d), (n))
-#define memmove(d,s,n) bcopy ((s), (d), (n))
-#endif /* ! HAVE_MEMCPY */
-#endif /* STDC_HEADERS */
-
#include <utime.h>
#include <errno.h>
#include <sys/param.h>
#include <atalk/unix.h>
#include "directory.h"
+#include "dircache.h"
#include "desktop.h"
#include "volume.h"
#include "fork.h"
(1 << FILPBIT_FNUM) |\
(1 << FILPBIT_UNIXPR)))
-/* -------------------------- */
-u_int32_t get_id(const struct vol *vol, struct adouble *adp, const struct stat *st,
- const cnid_t did, char *upath, const int len)
+/*!
+ * @brief Get CNID for did/upath args both from database and adouble file
+ *
+ * 1. Get the objects CNID as stored in its adouble file
+ * 2. Get the objects CNID from the database
+ * 3. If there's a problem with a "dbd" database, fallback to "tdb" in memory
+ * 4. In case 2 and 3 differ, store 3 in the adouble file
+ *
+ * @param vol (rw) volume
+ * @param adp (rw) adouble struct of object upath, might be NULL
+ * @param st (r) stat of upath, must NOT be NULL
+ * @param did (r) parent CNID of upath
+ * @param upath (r) name of object
+ * @param len (r) strlen of upath
+ */
+uint32_t get_id(struct vol *vol,
+ struct adouble *adp,
+ const struct stat *st,
+ const cnid_t did,
+ const char *upath,
+ const int len)
{
+ static int first = 1; /* mark if this func is called the first time */
u_int32_t adcnid;
u_int32_t dbcnid = CNID_INVALID;
+restart:
if (vol->v_cdb != NULL) {
/* prime aint with what we think is the cnid, set did to zero for
catching moved files */
- adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp);
+ adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */
- dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid);
+ dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */
/* Throw errors if cnid_add fails. */
if (dbcnid == CNID_INVALID) {
switch (errno) {
case CNID_ERR_PARAM:
LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add");
afp_errno = AFPERR_PARAM;
- return CNID_INVALID;
+ goto exit;
case CNID_ERR_PATH:
afp_errno = AFPERR_PARAM;
- return CNID_INVALID;
+ goto exit;
default:
+ /* Close CNID backend if "dbd" and switch to temp in-memory "tdb" */
+ /* we have to do it here for "dbd" because it uses "lazy opening" */
+ /* In order to not end in a loop somehow with goto restart below */
+ /* */
+ if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) { /* (3) */
+ cnid_close(vol->v_cdb);
+ free(vol->v_cnidscheme);
+ vol->v_cnidscheme = strdup("tdb");
+
+ int flags = CNID_FLAG_MEMORY;
+ if ((vol->v_flags & AFPVOL_NODEV)) {
+ flags |= CNID_FLAG_NODEV;
+ }
+ LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
+ vol->v_path);
+ vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL);
+ if (vol->v_cdb) {
+ /* deactivate cnid caching/storing in AppleDouble files and set ro mode*/
+ vol->v_flags &= ~AFPVOL_CACHE;
+ vol->v_flags |= AFPVOL_RO;
+#ifdef SERVERTEXT
+ /* kill ourself with SIGUSR2 aka msg pending */
+ setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB instead."
+ "Check server messages for details. Switching to read-only mode.");
+ kill(getpid(), SIGUSR2);
+#endif
+ goto restart; /* not try again with the temp CNID db */
+ } else {
+#ifdef SERVERTEXT
+ setmessage("Something wrong with the volume's CNID DB, using temporary CNID DB failed too!"
+ "Check server messages for details, can't recover from this state!");
+#endif
+ }
+ }
afp_errno = AFPERR_MISC;
- return CNID_INVALID;
+ goto exit;
}
}
- else if (adp && (adcnid != dbcnid)) {
+ else if (adp && (adcnid != dbcnid)) { /* 4 */
/* Update the ressource fork. For a folder adp is always null */
- LOG(log_debug, logtype_afpd, "get_id: calling ad_setid. adcnid: %u, dbcnid: %u", htonl(adcnid), htonl(dbcnid));
+ LOG(log_debug, logtype_afpd, "get_id(%s/%s): calling ad_setid(old: %u, new: %u)",
+ getcwdpath(), upath, htonl(adcnid), htonl(dbcnid));
if (ad_setid(adp, st->st_dev, st->st_ino, dbcnid, did, vol->v_stamp)) {
ad_flush(adp);
}
}
}
+
+exit:
+ first = 0;
return dbcnid;
}
struct stat *st;
struct maccess ma;
-
upath = path->u_name;
st = &path->st;
-
data = buf;
if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <<FILPBIT_PDINFO) ) ) && !path->m_name)
|| (bitmap & ( (1 << FILPBIT_LNAME) ) && utf8_encoding()) /* FIXME should be m_name utf8 filename */
|| (bitmap & (1 << FILPBIT_FNUM))) {
- if (!path->id)
- id = get_id(vol, adp, st, dir->d_did, upath, strlen(upath));
- else
+ if (!path->id) {
+ struct dir *cachedfile;
+ int len = strlen(upath);
+ if ((cachedfile = dircache_search_by_name(vol, dir, upath, len, st->st_ctime)) != NULL)
+ id = cachedfile->d_did;
+ else {
+ id = get_id(vol, adp, st, dir->d_did, upath, len);
+
+ /* Add it to the cache */
+ LOG(log_debug, logtype_afpd, "getmetadata: caching: did:%u, \"%s\", cnid:%u",
+ ntohl(dir->d_did), upath, ntohl(id));
+
+ /* Get macname from unixname first */
+ if (path->m_name == NULL) {
+ if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) {
+ LOG(log_error, logtype_afpd, "getmetadata: utompath error");
+ exit(EXITERR_SYS);
+ }
+ }
+
+ if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, NULL, st->st_ctime)) == NULL) {
+ LOG(log_error, logtype_afpd, "getmetadata: error from dir_new");
+ exit(EXITERR_SYS);
+ }
+
+ if ((dircache_add(cachedfile)) != 0) {
+ LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error");
+ exit(EXITERR_SYS);
+ }
+ }
+ } else {
id = path->id;
+ }
+
if (id == CNID_INVALID)
return afp_errno;
+
if (!path->m_name) {
path->m_name = utompath(vol, upath, id, utf8_encoding());
}
if (opened) {
char *upath;
- int flags = (bitmap & (1 << FILPBIT_ATTR))?ADFLAGS_OPENFORKS:0;
+ int flags = (bitmap & (1 << FILPBIT_ATTR)) ? ADFLAGS_CHECK_OF : 0;
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 ) {
- ad_close_metadata( adp);
- }
+ ad_close_metadata( adp);
return( rc );
}
/* ----------------------------- */
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++;
-#ifdef DROPKLUDGE
- if (vol->v_flags & AFPVOL_DROPBOX) {
- retvalue = matchfile2dirperms(upath, vol, did);
- }
-#endif /* DROPKLUDGE */
-
setvoltime(obj, vol );
return (retvalue);
/* 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:
}
LOG(log_debug, logtype_afpd, "setfilparams: no adouble perms, but only FILPBIT_MDATE and/or FILPBIT_UNIXPR");
isad = 0;
- } else if ((ad_get_HF_flags( adp ) & O_CREAT) ) {
+ } else if ((ad_get_MD_flags( adp ) & O_CREAT) ) {
ad_setname(adp, path->m_name);
}
if (isad) {
ad_flush( adp);
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)) {
+ /* don't care if we can't open the newly renamed ressource fork */
+ 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 ||
- getforkmode(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
+ denyreadset = (ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 ||
+ ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 );
if (denyreadset) {
retvalue = AFPERR_DENYCONF;
goto copy_exit;
}
-#ifdef FORCE_UIDGID
- /* FIXME svid != dvid && dvid's user can't read svid */
-#endif
if (NULL == ( d_vol = getvolbyvid( dvid )) ) {
retvalue = AFPERR_PARAM;
goto copy_exit;
}
curdir->offcnt++;
-#ifdef DROPKLUDGE
- if (vol->v_flags & AFPVOL_DROPBOX) {
- retvalue=matchfile2dirperms(upath, vol, ddid); /* FIXME sdir or ddid */
- }
-#endif /* DROPKLUDGE */
-
setvoltime(obj, d_vol );
copy_exit:
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, 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) {
* moreover sometimes deletefile is called with a no existent file and
* ad_open would create a 0 byte resource fork
*/
- if ( ad_metadataat(dirfd, file, ADFLAGS_OPENFORKS, &ad) == 0 ) {
+ if ( ad_metadataat(dirfd, file, ADFLAGS_CHECK_OF, &ad) == 0 ) {
if ((err = check_attrib(&ad))) {
ad_close_metadata(&ad);
return 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, 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's need switching. src -> dest and dest -> src.
* we need to re-stat() if it was a cross device copy.
*/
- if (sid) {
- cnid_delete(vol->v_cdb, sid);
- }
- if (did) {
- cnid_delete(vol->v_cdb, did);
- }
+ if (sid)
+ cnid_delete(vol->v_cdb, sid);
+ if (did)
+ cnid_delete(vol->v_cdb, did);
+
if ((did && ( (crossdev && lstat( upath, &srcst) < 0) ||
cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0))
||
ad_close(addp, ADFLAGS_HF);
}
+ struct dir *cached;
+ if ((cached = dircache_search_by_did(vol, sid)) != NULL)
+ (void)dir_remove(vol, cached);
+ if ((cached = dircache_search_by_did(vol, did)) != NULL)
+ (void)dir_remove(vol, cached);
+
return err;
}