X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Ffile.c;h=efc002bc0bfd11eb8797e8046b1aa71bda92e240;hb=18f2ef43a479721553a989931d8c60e84c5e1cac;hp=b277938c2fdd247e7da583c7f1ca4fa795ae3894;hpb=1da8848e568f9eb0a838cd3a6628a0709893abdd;p=netatalk.git diff --git a/etc/afpd/file.c b/etc/afpd/file.c index b277938c..efc002bc 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,6 +1,4 @@ /* - * $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. */ @@ -39,14 +37,16 @@ char *strchr (), *strrchr (); #include #include #include +#include +#include #include "directory.h" +#include "dircache.h" #include "desktop.h" #include "volume.h" #include "fork.h" #include "file.h" #include "filedir.h" -#include "globals.h" #include "unix.h" /* the format for the finderinfo fields (from IM: Toolbox Essentials): @@ -166,8 +166,8 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t else { u_int16_t temp; - if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/ - aint = 255; + if (aint > UTF8FILELEN_EARLY) /* FIXME safeguard, anyway if no ascii char it's game over*/ + aint = UTF8FILELEN_EARLY; utf8 = vol->v_kTextEncoding; memcpy(data, &utf8, sizeof(utf8)); @@ -201,9 +201,27 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t (1 << FILPBIT_FNUM) |\ (1 << FILPBIT_UNIXPR))) -/* -------------------------- */ -uint32_t get_id(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; @@ -213,9 +231,9 @@ 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) { @@ -233,7 +251,7 @@ restart: /* 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)) { + if (first && (strcmp(vol->v_cnidscheme, "dbd") == 0)) { /* (3) */ cnid_close(vol->v_cdb); free(vol->v_cnidscheme); vol->v_cnidscheme = strdup("tdb"); @@ -246,30 +264,27 @@ restart: 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 */ + if (!(vol->v_flags & AFPVOL_TM)) { + vol->v_flags |= AFPVOL_RO; + 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); + } + goto restart; /* now 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; 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); } @@ -298,21 +313,61 @@ int getmetadata(struct vol *vol, struct stat *st; struct maccess ma; + LOG(log_debug, logtype_afpd, "getmetadata(\"%s\")", path->u_name); upath = path->u_name; st = &path->st; - data = buf; if ( ((bitmap & ( (1 << FILPBIT_FINFO)|(1 << FILPBIT_LNAME)|(1 <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) { + bstring fullpath; + struct dir *cachedfile; + int len = strlen(upath); + if ((cachedfile = dircache_search_by_name(vol, dir, upath, len)) != 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"); + return AFPERR_MISC; + } + } + + /* Build fullpath */ + if (((fullpath = bstrcpy(dir->d_fullpath)) == NULL) + || (bconchar(fullpath, '/') != BSTR_OK) + || (bcatcstr(fullpath, upath)) != BSTR_OK) { + LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno)); + return AFPERR_MISC; + } + + if ((cachedfile = dir_new(path->m_name, upath, vol, dir->d_did, id, fullpath, st)) == NULL) { + LOG(log_error, logtype_afpd, "getmetadata: error from dir_new"); + return AFPERR_MISC; + } + + if ((dircache_add(vol, cachedfile)) != 0) { + LOG(log_error, logtype_afpd, "getmetadata: fatal dircache error"); + return AFPERR_MISC; + } + } + } else { id = path->id; + } + if (id == CNID_INVALID) return afp_errno; + if (!path->m_name) { path->m_name = utompath(vol, upath, id, utf8_encoding()); } @@ -335,9 +390,9 @@ int getmetadata(struct vol *vol, /* FIXME do we want a visual clue if the file is read only */ struct maccess ma; - accessmode( ".", &ma, dir , NULL); + accessmode(vol, ".", &ma, dir , NULL); if ((ma.ma_user & AR_UWRITE)) { - accessmode( upath, &ma, dir , st); + accessmode(vol, upath, &ma, dir , st); if (!(ma.ma_user & AR_UWRITE)) { ashort |= htons(ATTRBIT_NOWRITE); } @@ -504,7 +559,7 @@ int getmetadata(struct vol *vol, break; case FILPBIT_UNIXPR : /* accessmode may change st_mode with ACLs */ - accessmode( upath, &ma, dir , st); + accessmode(vol, upath, &ma, dir , st); aint = htonl(st->st_uid); memcpy( data, &aint, sizeof( aint )); @@ -566,6 +621,8 @@ int getfilparams(struct vol *vol, int opened = 0; int rc; + LOG(log_debug, logtype_afpd, "getfilparams(\"%s\")", path->u_name); + opened = PARAM_NEED_ADP(bitmap); adp = NULL; @@ -699,11 +756,25 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, path = s_path->m_name; ad_setname(adp, path); + + struct stat st; + if (lstat(upath, &st) != 0) { + LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): stat: %s", + upath, strerror(errno)); + ad_close( adp, ADFLAGS_DF|ADFLAGS_HF); + return AFPERR_MISC; + } + + (void)get_id(vol, adp, &st, dir->d_did, upath, strlen(upath)); + ad_flush( adp); + + fce_register_new_file(s_path); + ad_close( adp, ADFLAGS_DF|ADFLAGS_HF ); createfile_done: - curdir->offcnt++; + curdir->d_offcnt++; #ifdef DROPKLUDGE if (vol->v_flags & AFPVOL_DROPBOX) { @@ -1050,6 +1121,9 @@ int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *n { int rc; + LOG(log_debug, logtype_afpd, + "renamefile: src[%d, \"%s\"] -> dst[\"%s\"]", sdir_fd, src, dst); + if ( unix_rename( sdir_fd, src, -1, dst ) < 0 ) { switch ( errno ) { case ENOENT : @@ -1297,7 +1371,7 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si retvalue = err; goto copy_exit; } - curdir->offcnt++; + curdir->d_offcnt++; #ifdef DROPKLUDGE if (vol->v_flags & AFPVOL_DROPBOX) { @@ -1477,7 +1551,8 @@ int copyfile(const struct vol *s_vol, if (ad_reso_fileno(adp) == -1 || 0 == (err = copy_fork(ADEID_RFORK, &add, adp))){ /* copy the data fork */ if ((err = copy_fork(ADEID_DFORK, &add, adp)) == 0) { - err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst); + if (ad_meta_fileno(adp) != -1) + err = d_vol->vfs->vfs_copyfile(d_vol, sfd, src, dst); } } @@ -1781,7 +1856,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir) if (dirreenumerate(dir, &st)) { /* we already did it once and the dir haven't been modified */ - return dir->offcnt; + return dir->d_offcnt; } data.vol = vol; @@ -2189,12 +2264,11 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* 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)) || @@ -2288,5 +2362,11 @@ err_exchangefile: 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; }