X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Ffile.c;h=edb55ea3eafced56c9464077a45360266f444779;hp=14906d294f124d800a43493450901299f606d0dc;hb=4021b76ce3f3e51756e9d59b4a5a045ad6398dc8;hpb=f80fc8f0e51cef12a2902c0ad7f8a45b5682ec9d diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 14906d29..edb55ea3 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "directory.h" #include "dircache.h" @@ -76,10 +78,10 @@ static int default_type(void *finder) /* FIXME path : unix or mac name ? (for now it's unix name ) */ void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data, int islink) { - struct extmap *em; + struct extmap *em; void *ad_finder = NULL; int chk_ext = 0; - + if (adp) ad_finder = ad_entry(adp, ADEID_FINDERI); @@ -100,14 +102,13 @@ void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *a } } - if (islink){ + if (islink && !vol_syml_opt(vol)) { uint16_t linkflag; memcpy(&linkflag, (char *)data + FINDERINFO_FRFLAGOFF, 2); linkflag |= htons(FINDERINFO_ISALIAS); memcpy((char *)data + FINDERINFO_FRFLAGOFF, &linkflag, 2); memcpy((char *)data + FINDERINFO_FRTYPEOFF,"slnk",4); memcpy((char *)data + FINDERINFO_FRCREATOFF,"rhap",4); - chk_ext = 0; } /** Only enter if no appledouble information and no finder information found. */ @@ -115,6 +116,7 @@ void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *a memcpy(data, em->em_type, sizeof( em->em_type )); memcpy((char *)data + 4, em->em_creator, sizeof(em->em_creator)); } + return data; } @@ -129,7 +131,7 @@ char *set_name(const struct vol *vol, char *data, cnid_t pid, char *name, cnid_t if (!utf8) { /* want mac name */ - if (utf8_encoding()) { + if (utf8_encoding(vol->v_obj)) { /* but name is an utf8 mac name */ char *u, *m; @@ -218,7 +220,10 @@ restart: catching moved files */ adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */ + AFP_CNID_START("cnid_add"); dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */ + AFP_CNID_DONE(); + /* Throw errors if cnid_add fails. */ if (dbcnid == CNID_INVALID) { switch (errno) { @@ -249,33 +254,29 @@ 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)) { /* 4 */ + else if (adp && adcnid && (adcnid != dbcnid)) { /* 4 */ /* Update the ressource fork. For a folder adp is always null */ 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); + if (ad_flush(adp) != 0) + LOG(log_error, logtype_afpd, "get_id(\"%s\"): can't flush", fullpathname(upath)); } } } @@ -286,10 +287,11 @@ exit: } /* -------------------------- */ -int getmetadata(struct vol *vol, - uint16_t bitmap, - struct path *path, struct dir *dir, - char *buf, size_t *buflen, struct adouble *adp) +int getmetadata(const AFPObj *obj, + struct vol *vol, + uint16_t bitmap, + struct path *path, struct dir *dir, + char *buf, size_t *buflen, struct adouble *adp) { char *data, *l_nameoff = NULL, *upath; char *utf_nameoff = NULL; @@ -309,7 +311,7 @@ int getmetadata(struct vol *vol, 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_LNAME) ) && utf8_encoding(obj)) /* FIXME should be m_name utf8 filename */ || (bitmap & (1 << FILPBIT_FNUM))) { if (!path->id) { bstring fullpath; @@ -326,7 +328,7 @@ int getmetadata(struct vol *vol, /* Get macname from unixname first */ if (path->m_name == NULL) { - if ((path->m_name = utompath(vol, upath, id, utf8_encoding())) == NULL) { + if ((path->m_name = utompath(vol, upath, id, utf8_encoding(obj))) == NULL) { LOG(log_error, logtype_afpd, "getmetadata: utompath error"); return AFPERR_MISC; } @@ -337,6 +339,7 @@ int getmetadata(struct vol *vol, || (bconchar(fullpath, '/') != BSTR_OK) || (bcatcstr(fullpath, upath)) != BSTR_OK) { LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno)); + bdestroy(fullpath); return AFPERR_MISC; } @@ -358,7 +361,7 @@ int getmetadata(struct vol *vol, return afp_errno; if (!path->m_name) { - path->m_name = utompath(vol, upath, id, utf8_encoding()); + path->m_name = utompath(vol, upath, id, utf8_encoding(vol->v_obj)); } } while ( bitmap != 0 ) { @@ -375,6 +378,7 @@ int getmetadata(struct vol *vol, ashort = htons(ATTRBIT_INVISIBLE); } else ashort = 0; + ashort &= ~htons(vol->v_ignattr); #if 0 /* FIXME do we want a visual clue if the file is read only */ @@ -457,18 +461,23 @@ int getmetadata(struct vol *vol, data += sizeof( aint ); break; - case FILPBIT_RFLEN : - if ( adp ) { + case FILPBIT_RFLEN: { + off_t rlen; + if (adp) { if (adp->ad_rlen > 0xffffffff) aint = 0xffffffff; else aint = htonl( adp->ad_rlen); } else { - aint = 0; + rlen = ad_reso_size(path->u_name, 0, NULL); + if (rlen > 0xffffffff) + rlen = 0xffffffff; + aint = htonl(rlen); } memcpy(data, &aint, sizeof( aint )); data += sizeof( aint ); break; + } /* Current client needs ProDOS info block for this file. Use simple heuristic and let the Mac "type" string tell @@ -477,7 +486,7 @@ int getmetadata(struct vol *vol, to "pXYZ" when we created it. See IA, Ver 2. */ case FILPBIT_PDINFO : - if (afp_version >= 30) { /* UTF8 name */ + if (obj->afp_version >= 30) { /* UTF8 name */ utf8 = kTextEncodingUTF8; utf_nameoff = data; data += sizeof( uint16_t ); @@ -536,19 +545,22 @@ int getmetadata(struct vol *vol, data += sizeof( aint ); break; case FILPBIT_EXTRFLEN: - aint = 0; - if (adp) + if (adp) { aint = htonl(adp->ad_rlen >> 32); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - if (adp) + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); aint = htonl(adp->ad_rlen); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); + } else { + int64_t rlen = hton64(ad_reso_size(path->u_name, 0, NULL)); + memcpy(data, &rlen, sizeof(rlen)); + data += sizeof(rlen); + } break; case FILPBIT_UNIXPR : /* accessmode may change st_mode with ACLs */ - accessmode(vol, upath, &ma, dir , st); + accessmode(obj, vol, upath, &ma, dir , st); aint = htonl(st->st_uid); memcpy( data, &aint, sizeof( aint )); @@ -601,15 +613,13 @@ int getmetadata(struct vol *vol, } /* ----------------------- */ -int getfilparams(struct vol *vol, - uint16_t bitmap, - struct path *path, struct dir *dir, - char *buf, size_t *buflen ) +int getfilparams(const AFPObj *obj, struct vol *vol, uint16_t bitmap, struct path *path, + struct dir *dir, char *buf, size_t *buflen, int in_enumerate) { struct adouble ad, *adp; int opened = 0; int rc; - int flags; + int flags; /* uninitialized ok */ LOG(log_debug, logtype_afpd, "getfilparams(\"%s\")", path->u_name); @@ -618,7 +628,12 @@ int getfilparams(struct vol *vol, if (opened) { char *upath; - flags = (bitmap & (1 << FILPBIT_ATTR)) ? ADFLAGS_CHECK_OF : 0; + /* + * Dont check for and resturn open fork attributes when enumerating + * This saves a lot of syscalls, the client will hopefully only use the result + * in FPGetFileParms where we return the correct value + */ + flags = (!in_enumerate &&(bitmap & (1 << FILPBIT_ATTR))) ? ADFLAGS_CHECK_OF : 0; adp = of_ad(vol, path, &ad); upath = path->u_name; @@ -639,8 +654,10 @@ int getfilparams(struct vol *vol, } } } - rc = getmetadata(vol, bitmap, path, dir, buf, buflen, adp); - ad_close(adp, ADFLAGS_HF | flags); + rc = getmetadata(obj, vol, bitmap, path, dir, buf, buflen, adp); + + if (opened) + ad_close(adp, ADFLAGS_HF | flags); return( rc ); } @@ -685,7 +702,7 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, ad_init(&ad, vol); /* if upath is deleted we already in trouble anyway */ - if ((of = of_findname(s_path))) { + if ((of = of_findname(vol, s_path))) { if (creatf) return AFPERR_BUSY; else @@ -711,6 +728,7 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, return( AFPERR_ACCESS ); case EDQUOT: case ENOSPC : + LOG(log_info, logtype_afpd, "afp_createfile: DISK FULL"); return( AFPERR_DFULL ); default : return( AFPERR_PARAM ); @@ -736,15 +754,20 @@ int afp_createfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, return AFPERR_MISC; } - (void)get_id(vol, &ad, &st, dir->d_did, upath, strlen(upath)); + cnid_t id; + if ((id = get_id(vol, &ad, &st, dir->d_did, upath, strlen(upath))) == CNID_INVALID) { + LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): CNID error", upath); + goto createfile_iderr; + } + (void)ad_setid(&ad, st.st_dev, st.st_ino, id, dir->d_did, vol->v_stamp); +createfile_iderr: ad_flush(&ad); ad_close(&ad, ADFLAGS_DF|ADFLAGS_HF ); - fce_register_new_file(s_path); + fce_register(FCE_FILE_CREATE, fullpathname(upath), NULL, fce_file); + sl_index_file(path); -createfile_done: curdir->d_offcnt++; - setvoltime(obj, vol ); return (retvalue); @@ -796,7 +819,7 @@ int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ ibuf++; } - if (AFP_OK == ( rc = setfilparams(vol, s_path, bitmap, ibuf )) ) { + if (AFP_OK == ( rc = setfilparams(obj, vol, s_path, bitmap, ibuf )) ) { setvoltime(obj, vol ); } @@ -809,7 +832,7 @@ int afp_setfilparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ */ extern struct path Cur_Path; -int setfilparams(struct vol *vol, +int setfilparams(const AFPObj *obj, struct vol *vol, struct path *path, uint16_t f_bitmap, char *buf ) { struct adouble ad, *adp; @@ -831,7 +854,10 @@ int setfilparams(struct vol *vol, uint16_t bitmap = f_bitmap; uint32_t cdate,bdate; u_char finder_buf[32]; - int symlinked = 0; + int symlinked = S_ISLNK(path->st.st_mode); + int fp; + ssize_t len; + char symbuf[MAXPATHLEN+1]; #ifdef DEBUG LOG(log_debug9, logtype_afpd, "begin setfilparams:"); @@ -840,7 +866,7 @@ int setfilparams(struct vol *vol, adp = of_ad(vol, path, &ad); upath = path->u_name; - if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) { + if (!vol_unix_priv(vol) && check_access(obj, vol, upath, OPENACC_WR ) < 0) { return AFPERR_ACCESS; } @@ -873,29 +899,33 @@ int setfilparams(struct vol *vol, break; case FILPBIT_FINFO : change_mdate = 1; - memcpy(finder_buf, buf, 32 ); - if (memcmp(buf, "slnkrhap", 8) == 0 && !S_ISLNK(path->st.st_mode)) { - int fp; - ssize_t len; - int erc=1; - char buf[PATH_MAX+1]; - if ((fp = open(path->u_name, O_RDONLY)) >= 0) { - if ((len = read(fp, buf, PATH_MAX+1))) { - if (unlink(path->u_name) == 0) { - buf[len] = 0; - erc = symlink(buf, path->u_name); - if (!erc) - of_stat(path); - } - } - close(fp); + if (memcmp(buf,"slnkrhap",8) == 0 + && !(S_ISLNK(path->st.st_mode)) + && !(vol->v_flags & AFPVOL_FOLLOWSYM)) { + /* request to turn this into a symlink */ + if ((fp = open(path->u_name, O_RDONLY)) == -1) { + err = AFPERR_MISC; + goto setfilparam_done; + } + len = read(fp, symbuf, MAXPATHLEN); + close(fp); + if (!(len > 0)) { + err = AFPERR_MISC; + goto setfilparam_done; + } + if (unlink(path->u_name) != 0) { + err = AFPERR_MISC; + goto setfilparam_done; } - if (erc != 0) { - err=AFPERR_BITMAP; + symbuf[len] = 0; + if (symlink(symbuf, path->u_name) != 0) { + err = AFPERR_MISC; goto setfilparam_done; } + of_stat(vol, path); symlinked = 1; } + memcpy(finder_buf, buf, 32 ); buf += 32; break; case FILPBIT_UNIXPR : @@ -928,7 +958,7 @@ int setfilparams(struct vol *vol, } break; case FILPBIT_PDINFO : - if (afp_version < 30) { /* else it's UTF8 name */ + if (obj->afp_version < 30) { /* else it's UTF8 name */ achar = *buf; buf += 2; /* Keep special case to support crlf translations */ @@ -973,6 +1003,12 @@ int setfilparams(struct vol *vol, isad = 0; } else if ((ad_get_MD_flags( adp ) & O_CREAT) ) { ad_setname(adp, path->m_name); + cnid_t id; + if ((id = get_id(vol, adp, &path->st, curdir->d_did, upath, strlen(upath))) == CNID_INVALID) { + LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): CNID error", upath); + return AFPERR_MISC; + } + (void)ad_setid(adp, path->st.st_dev, path->st.st_ino, id, curdir->d_did, vol->v_stamp); } bit = 0; @@ -988,6 +1024,7 @@ int setfilparams(struct vol *vol, ad_getattr(adp, &bshort); oshort = bshort; if ( ntohs( ashort ) & ATTRBIT_SETCLR ) { + ashort &= ~htons(vol->v_ignattr); bshort |= htons( ntohs( ashort ) & ~ATTRBIT_SETCLR ); } else { bshort &= ~ashort; @@ -1024,7 +1061,7 @@ int setfilparams(struct vol *vol, } break; case FILPBIT_PDINFO : - if (afp_version < 30) { /* else it's UTF8 name */ + if (obj->afp_version < 30) { /* else it's UTF8 name */ memcpy(ad_entry( adp, ADEID_FINDERI ), fdType, 4 ); memcpy(ad_entry( adp, ADEID_FINDERI ) + 4, "pdos", 4 ); break; @@ -1078,7 +1115,7 @@ setfilparam_done: * adp adouble struct of src file, if open, or & zeroed one * */ -int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp) +int renamefile(struct vol *vol, struct dir *ddir, int sdir_fd, char *src, char *dst, char *newname, struct adouble *adp) { int rc; @@ -1103,7 +1140,7 @@ int renamefile(const struct vol *vol, int sdir_fd, char *src, char *dst, char *n /* FIXME warning in syslog so admin'd know there's a conflict ?*/ return AFPERR_OLOCK; /* little lie */ } - if (AFP_OK != ( rc = copyfile(vol, vol, sdir_fd, src, dst, newname, NULL )) ) { + if (AFP_OK != ( rc = copyfile(vol, vol, ddir, sdir_fd, src, dst, newname, NULL )) ) { /* on error copyfile delete dest */ return( rc ); } @@ -1168,14 +1205,14 @@ size_t plen = 0; uint16_t len16; uint32_t hint; - if ( type != 2 && !(afp_version >= 30 && type == 3) ) { + if ( type != 2 && !(vol->v_obj->afp_version >= 30 && type == 3) ) { return -1; } ibuf++; switch (type) { case 2: if (( plen = (unsigned char)*ibuf++ ) != 0 ) { - if (afp_version >= 30) { + if (vol->v_obj->afp_version >= 30) { /* convert it to UTF8 */ if ((plen = mtoUTF8(vol, ibuf, plen, newname, AFPOBJ_TMPSIZ)) == (size_t)-1) @@ -1269,6 +1306,19 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si if (ad_open(adp, s_path->u_name, ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) { return AFPERR_DENYCONF; } +#ifdef HAVE_FSHARE_T + fshare_t shmd; + shmd.f_access = F_RDACC; + shmd.f_deny = F_NODNY; + if (fcntl(ad_data_fileno(adp), F_SHARE, &shmd) != 0) { + retvalue = AFPERR_DENYCONF; + goto copy_exit; + } + if (AD_RSRC_OPEN(adp) && fcntl(ad_reso_fileno(adp), F_SHARE, &shmd) != 0) { + retvalue = AFPERR_DENYCONF; + goto copy_exit; + } +#endif denyreadset = (ad_testlock(adp, ADEID_DFORK, AD_FILELOCK_DENY_RD) != 0 || ad_testlock(adp, ADEID_RFORK, AD_FILELOCK_DENY_RD) != 0 ); @@ -1319,12 +1369,12 @@ int afp_copyfile(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si /* newname is always only a filename so curdir *is* its * parent folder */ - if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding()))) { + if (NULL == (upath = mtoupath(d_vol, newname, curdir->d_did, utf8_encoding(d_vol->v_obj)))) { retvalue =AFPERR_PARAM; goto copy_exit; } - if ( (err = copyfile(s_vol, d_vol, -1, p, upath , newname, adp)) < 0 ) { + if ( (err = copyfile(s_vol, d_vol, curdir, -1, p, upath , newname, adp)) < 0 ) { retvalue = err; goto copy_exit; } @@ -1337,111 +1387,14 @@ copy_exit: return( retvalue ); } -/* ----------------------- */ -static int copy_all(const int dfd, const void *buf, - size_t buflen) -{ - ssize_t cc; - -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "begin copy_all:"); -#endif /* DEBUG */ - - while (buflen > 0) { - if ((cc = write(dfd, buf, buflen)) < 0) { - switch (errno) { - case EINTR: - continue; - default: - return -1; - } - } - buflen -= cc; - } - -#ifdef DEBUG - LOG(log_debug9, logtype_afpd, "end copy_all:"); -#endif /* DEBUG */ - - return 0; -} - -/* -------------------------- - * copy only the fork data stream -*/ -static int copy_fork(int eid, struct adouble *add, struct adouble *ads) -{ - ssize_t cc; - int err = 0; - char filebuf[8192]; - int sfd, dfd; - - if (eid == ADEID_DFORK) { - sfd = ad_data_fileno(ads); - dfd = ad_data_fileno(add); - } - else { - sfd = ad_reso_fileno(ads); - dfd = ad_reso_fileno(add); - } - - if ((off_t)-1 == lseek(sfd, ad_getentryoff(ads, eid), SEEK_SET)) - return -1; - - if ((off_t)-1 == lseek(dfd, ad_getentryoff(add, eid), SEEK_SET)) - return -1; - -#if 0 /* ifdef SENDFILE_FLAVOR_LINUX */ - /* doesn't work With 2.6 FIXME, only check for EBADFD ? */ - off_t offset = 0; - size_t size; - struct stat st; - #define BUF 128*1024*1024 - - if (fstat(sfd, &st) == 0) { - - while (1) { - if ( offset >= st.st_size) { - return 0; - } - size = (st.st_size -offset > BUF)?BUF:st.st_size -offset; - if ((cc = sys_sendfile(dfd, sfd, &offset, size)) < 0) { - switch (errno) { - case ENOSYS: - case EINVAL: /* there's no guarantee that all fs support sendfile */ - goto no_sendfile; - default: - return -1; - } - } - } - } - no_sendfile: - lseek(sfd, offset, SEEK_SET); -#endif - - while (1) { - if ((cc = read(sfd, filebuf, sizeof(filebuf))) < 0) { - if (errno == EINTR) - continue; - err = -1; - break; - } - - if (!cc || ((err = copy_all(dfd, filebuf, cc)) < 0)) { - break; - } - } - return err; -} - /* ---------------------------------- * if newname is NULL (from directory.c) we don't want to copy the resource fork. * because we are doing it elsewhere. * currently if newname is NULL then adp is NULL. */ -int copyfile(const struct vol *s_vol, - const struct vol *d_vol, +int copyfile(struct vol *s_vol, + struct vol *d_vol, + struct dir *d_dir, int sfd, char *src, char *dst, @@ -1463,13 +1416,17 @@ int copyfile(const struct vol *s_vol, adp = &ads; } - adflags = ADFLAGS_DF | ADFLAGS_RF | ADFLAGS_NORF; + adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF | ADFLAGS_RF | ADFLAGS_NORF; if (ad_openat(adp, sfd, src, adflags | ADFLAGS_RDONLY) < 0) { ret_err = errno; goto done; } + if (!AD_META_OPEN(adp)) + /* no resource fork, don't create one for dst file */ + adflags &= ~ADFLAGS_HF; + if (!AD_RSRC_OPEN(adp)) /* no resource fork, don't create one for dst file */ adflags &= ~ADFLAGS_RF; @@ -1502,12 +1459,25 @@ int copyfile(const struct vol *s_vol, if (err < 0) ret_err = errno; - if (!ret_err && newname && (adflags & ADFLAGS_HF)) { - /* set the new name in the resource fork */ - ad_copy_header(&add, adp); - ad_setname(&add, newname); - ad_flush( &add ); + if (AD_META_OPEN(&add)) { + if (AD_META_OPEN(adp)) + ad_copy_header(&add, adp); + ad_setname(&add, dst); + cnid_t id; + struct stat stdest; + if (fstat(ad_meta_fileno(&add), &stdest) != 0) { + ret_err = errno; + goto error; + } + if ((id = get_id(d_vol, &add, &stdest, d_dir->d_did, dst, strlen(dst))) == CNID_INVALID) { + ret_err = EINVAL; + goto error; + } + (void)ad_setid(&add, stdest.st_dev, stdest.st_ino, id, d_dir->d_did, d_vol->v_stamp); + ad_flush(&add); } + +error: ad_close( adp, adflags ); if (ad_close( &add, adflags ) <0) { @@ -1535,6 +1505,7 @@ done: case EDQUOT: case EFBIG: case ENOSPC: + LOG(log_info, logtype_afpd, "copyfile: DISK FULL"); return AFPERR_DFULL; case ENOENT: return AFPERR_NOOBJ; @@ -1558,7 +1529,7 @@ done: WRITE lock on read only file. */ -static int check_attrib(struct adouble *adp) +static int check_attrib(const struct vol *vol, struct adouble *adp) { uint16_t bshort = 0; @@ -1566,10 +1537,10 @@ uint16_t bshort = 0; /* * Does kFPDeleteInhibitBit (bit 8) set? */ - if ((bshort & htons(ATTRBIT_NODELETE))) { + if (!(vol->v_ignattr & ATTRBIT_NODELETE) && (bshort & htons(ATTRBIT_NODELETE))) { return AFPERR_OLOCK; } - if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) { + if ((bshort & htons(ATTRBIT_DOPEN | ATTRBIT_ROPEN))) { return AFPERR_BUSY; } return 0; @@ -1594,7 +1565,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) * ad_open would create a 0 byte resource fork */ if ( ad_metadataat(dirfd, file, ADFLAGS_CHECK_OF, &ad) == 0 ) { - if ((err = check_attrib(&ad))) { + if ((err = check_attrib(vol, &ad))) { ad_close(&ad, ADFLAGS_HF | ADFLAGS_CHECK_OF); return err; } @@ -1623,7 +1594,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) adp = &ad; } - if ( adp && AD_RSRC_OPEN(adp) != -1 ) { /* there's a resource fork */ + if ( adp && AD_RSRC_OPEN(adp) ) { /* there's a resource fork */ adflags |= ADFLAGS_RF; /* FIXME we have a pb here because we want to know if a file is open * there's a 'priority inversion' if you can't open the ressource fork RW @@ -1645,8 +1616,15 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) err = AFPERR_BUSY; } else if (!(err = vol->vfs->vfs_deletefile(vol, dirfd, file)) && !(err = netatalk_unlinkat(dirfd, file )) ) { cnid_t id; - if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) { - cnid_delete(vol->v_cdb, id); + if (checkAttrib) { + AFP_CNID_START("cnid_get"); + id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)); + AFP_CNID_DONE(); + if (id) { + AFP_CNID_START("cnid_delete"); + cnid_delete(vol->v_cdb, id); + AFP_CNID_DONE(); + } } } @@ -1719,7 +1697,10 @@ int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si return AFPERR_PARAM; } st = &s_path->st; - if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) { + AFP_CNID_START("cnid_lookup"); + id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)); + AFP_CNID_DONE(); + if (id) { memcpy(rbuf, &id, sizeof(id)); *rbuflen = sizeof(id); return AFPERR_EXISTID; @@ -1748,11 +1729,13 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data) cnid_t did = param->did; cnid_t aint; - if ( lstat(de->d_name, &path.st) < 0 ) + if (ostat(de->d_name, &path.st, vol_syml_opt(vol)) < 0) return 0; /* update or add to cnid */ + AFP_CNID_START("cnid_add"); aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */ + AFP_CNID_DONE(); return 0; } @@ -1773,7 +1756,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir) } /* FIXME use of_statdir ? */ - if (lstat(name, &st)) { + if (ostat(name, &st, vol_syml_opt(vol))) { return -1; } @@ -1794,7 +1777,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir) /* ------------------------------ resolve a file id */ -int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) +int afp_resolveid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) { struct vol *vol; struct dir *dir; @@ -1831,7 +1814,10 @@ int afp_resolveid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, s return AFPERR_NOID; } retry: - if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) { + AFP_CNID_START("cnid_resolve"); + upath = cnid_resolve(vol->v_cdb, &id, buffer, len); + AFP_CNID_DONE(); + if (upath == NULL) { return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */ } @@ -1852,7 +1838,7 @@ retry: memset(&path, 0, sizeof(path)); path.u_name = upath; - if ( of_stat(&path) < 0 ) { + if (of_stat(vol, &path) < 0 ) { #ifdef ESTALE /* with nfs and our working directory is deleted */ if (errno == ESTALE) { @@ -1880,17 +1866,17 @@ retry: /* directories are bad */ if (S_ISDIR(path.st.st_mode)) { /* OS9 and OSX don't return the same error code */ - return (afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE; + return (obj->afp_version >=30)?AFPERR_NOID:AFPERR_BADTYPE; } memcpy(&bitmap, ibuf, sizeof(bitmap)); bitmap = ntohs( bitmap ); - if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding()))) { + if (NULL == (path.m_name = utompath(vol, upath, cnid, utf8_encoding(obj)))) { return AFPERR_NOID; } path.id = cnid; - if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, - rbuf + sizeof(bitmap), &buflen))) { + if (AFP_OK != (err = getfilparams(obj, vol, bitmap, &path , curdir, + rbuf + sizeof(bitmap), &buflen, 0))) { return err; } *rbuflen = buflen + sizeof(bitmap); @@ -1934,7 +1920,10 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ ibuf += sizeof(id); fileid = id; - if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) { + AFP_CNID_START("cnid_resolve"); + upath = cnid_resolve(vol->v_cdb, &id, buffer, len); + AFP_CNID_DONE(); + if (upath == NULL) { return AFPERR_NOID; } @@ -1947,7 +1936,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ } err = AFP_OK; - if ((movecwd(vol, dir) < 0) || (lstat(upath, &st) < 0)) { + if ((movecwd(vol, dir) < 0) || (ostat(upath, &st, vol_syml_opt(vol)) < 0)) { switch (errno) { case EACCES: case EPERM: @@ -1967,7 +1956,9 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ return AFPERR_BADTYPE; delete: + AFP_CNID_START("cnid_delete"); if (cnid_delete(vol->v_cdb, fileid)) { + AFP_CNID_DONE(); switch (errno) { case EROFS: return AFPERR_VLOCK; @@ -1978,12 +1969,12 @@ delete: return AFPERR_PARAM; } } - + AFP_CNID_DONE(); return err; } /* ------------------------------ */ -static struct adouble *find_adouble(struct path *path, struct ofork **of, struct adouble *adp) +static struct adouble *find_adouble(const AFPObj *obj, struct vol *vol, struct path *path, struct ofork **of, struct adouble *adp) { int ret; @@ -2005,12 +1996,12 @@ static struct adouble *find_adouble(struct path *path, struct ofork **of, struct /* we use file_access both for legacy Mac perm and * for unix privilege, rename will take care of folder perms */ - if (file_access(path, OPENACC_WR ) < 0) { + if (file_access(obj, vol, path, OPENACC_WR ) < 0) { afp_errno = AFPERR_ACCESS; return NULL; } - if ((*of = of_findname(path))) { + if ((*of = of_findname(vol, path))) { /* reuse struct adouble so it won't break locks */ adp = (*of)->of_ad; } @@ -2052,9 +2043,6 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U uint32_t sid, did; uint16_t vid; - uid_t uid; - gid_t gid; - *rbuflen = 0; ibuf += 2; @@ -2101,7 +2089,7 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U } ad_init(&ads, vol); - if (!(adsp = find_adouble( path, &s_of, &ads))) { + if (!(adsp = find_adouble(obj, vol, path, &s_of, &ads))) { return afp_errno; } @@ -2109,7 +2097,9 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* look for the source cnid. if it doesn't exist, don't worry about * it. */ + AFP_CNID_START("cnid_lookup"); sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath)); + AFP_CNID_DONE(); if (NULL == ( dir = dirlookup( vol, did )) ) { err = afp_errno; /* was AFPERR_PARAM */ @@ -2134,7 +2124,7 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U } ad_init(&add, vol); - if (!(addp = find_adouble( path, &d_of, &add))) { + if (!(addp = find_adouble(obj, vol, path, &d_of, &add))) { err = afp_errno; goto err_exchangefile; } @@ -2152,17 +2142,21 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* look for destination id. */ upath = path->u_name; + AFP_CNID_START("cnid_lookup"); did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath)); + AFP_CNID_DONE(); /* construct a temp name. * NOTE: the temp file will be in the dest file's directory. it * will also be inaccessible from AFP. */ memcpy(temp, APPLETEMP, sizeof(APPLETEMP)); - if (!mktemp(temp)) { + int fd; + if ((fd = mkstemp(temp)) == -1) { err = AFPERR_MISC; goto err_exchangefile; } - + close(fd); + if (crossdev) { /* FIXME we need to close fork for copy, both s_of and d_of are null */ ad_close(adsp, ADFLAGS_HF); @@ -2170,32 +2164,39 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U } /* now, quickly rename the file. we error if we can't. */ - if ((err = renamefile(vol, -1, p, temp, temp, adsp)) != AFP_OK) + if ((err = renamefile(vol, curdir, -1, p, temp, temp, adsp)) != AFP_OK) goto err_exchangefile; of_rename(vol, s_of, sdir, spath, curdir, temp); /* rename destination to source */ - if ((err = renamefile(vol, -1, upath, p, spath, addp)) != AFP_OK) + if ((err = renamefile(vol, curdir, -1, upath, p, spath, addp)) != AFP_OK) goto err_src_to_tmp; of_rename(vol, d_of, curdir, path->m_name, sdir, spath); /* rename temp to destination */ - if ((err = renamefile(vol, -1, temp, upath, path->m_name, adsp)) != AFP_OK) + if ((err = renamefile(vol, curdir, -1, temp, upath, path->m_name, adsp)) != AFP_OK) goto err_dest_to_src; of_rename(vol, s_of, curdir, temp, curdir, path->m_name); - /* id's need switching. src -> dest and dest -> src. + /* + * id's need switching. src -> dest and dest -> src. * we need to re-stat() if it was a cross device copy. - */ - if (sid) + */ + if (sid) { + AFP_CNID_START("cnid_delete"); cnid_delete(vol->v_cdb, sid); - if (did) + AFP_CNID_DONE(); + } + if (did) { + AFP_CNID_START("cnid_delete"); cnid_delete(vol->v_cdb, did); + AFP_CNID_DONE(); + } - if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || + if ((did && ( (crossdev && ostat(upath, &srcst, vol_syml_opt(vol)) < 0) || cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0)) || - (sid && ( (crossdev && lstat(p, &destst) < 0) || + (sid && ( (crossdev && ostat(p, &destst, vol_syml_opt(vol)) < 0) || cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0)) ) { switch (errno) { @@ -2208,6 +2209,42 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U } goto err_temp_to_dest; } + + if (AD_META_OPEN(adsp) || AD_META_OPEN(addp)) { + struct adouble adtmp; + bool opened_ads, opened_add; + + ad_init(&adtmp, vol); + ad_init_offsets(&adtmp); + + if (!AD_META_OPEN(adsp)) { + if (ad_open(adsp, p, ADFLAGS_HF) != 0) + return -1; + opened_ads = true; + } + + if (!AD_META_OPEN(addp)) { + if (ad_open(addp, upath, ADFLAGS_HF) != 0) + return -1; + opened_add = true; + } + + if (ad_copy_header(&adtmp, adsp) != 0) + goto err_temp_to_dest; + if (ad_copy_header(adsp, addp) != 0) + goto err_temp_to_dest; + if (ad_copy_header(addp, &adtmp) != 0) + goto err_temp_to_dest; + ad_flush(adsp); + ad_flush(addp); + + if (opened_ads) + ad_close(adsp, ADFLAGS_HF); + if (opened_add) + ad_close(addp, ADFLAGS_HF); + } + + /* FIXME: we should switch ressource fork too */ /* here we need to reopen if crossdev */ if (sid && ad_setid(addp, destst.st_dev, destst.st_ino, sid, sdir->d_did, vol->v_stamp)) @@ -2222,13 +2259,7 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* change perms, src gets dest perm and vice versa */ - uid = geteuid(); - gid = getegid(); - if (seteuid(0)) { - LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno)); - err = AFP_OK; /* ignore error */ - goto err_temp_to_dest; - } + become_root(); /* * we need to exchange ACL entries as well @@ -2252,10 +2283,7 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U setfilunixmode(vol, path, srcst.st_mode); setfilowner(vol, srcst.st_uid, srcst.st_gid, path); - if ( setegid(gid) < 0 || seteuid(uid) < 0) { - LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno)); - exit(EXITERR_SYS); - } + unbecome_root(); err = AFP_OK; goto err_exchangefile; @@ -2264,17 +2292,17 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U * properly. */ err_temp_to_dest: /* rename dest to temp */ - renamefile(vol, -1, upath, temp, temp, adsp); + renamefile(vol, curdir, -1, upath, temp, temp, adsp); of_rename(vol, s_of, curdir, upath, curdir, temp); err_dest_to_src: /* rename source back to dest */ - renamefile(vol, -1, p, upath, path->m_name, addp); + renamefile(vol, curdir, -1, p, upath, path->m_name, addp); of_rename(vol, d_of, sdir, spath, curdir, path->m_name); err_src_to_tmp: /* rename temp back to source */ - renamefile(vol, -1, temp, p, spath, adsp); + renamefile(vol, curdir, -1, temp, p, spath, adsp); of_rename(vol, s_of, curdir, temp, sdir, spath); err_exchangefile: