X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libatalk%2Fadouble%2Fad_write.c;h=4ae1cf60adf1cfcbd61907d20a5fc430c1f4d31a;hb=HEAD;hp=1331ae047d7e33c19a485b28fd347cc5735037f3;hpb=96afda34736f3aee95560c125e59211ab811e203;p=netatalk.git diff --git a/libatalk/adouble/ad_write.c b/libatalk/adouble/ad_write.c index 1331ae04..4ae1cf60 100644 --- a/libatalk/adouble/ad_write.c +++ b/libatalk/adouble/ad_write.c @@ -1,6 +1,4 @@ /* - * $Id: ad_write.c,v 1.9 2006-09-29 09:39:16 didg Exp $ - * * Copyright (c) 1990,1995 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ @@ -9,16 +7,18 @@ #include "config.h" #endif /* HAVE_CONFIG_H */ -#include - +#include #include #include #include - -#ifndef MIN -#define MIN(a,b) ((a)<(b)?(a):(b)) -#endif /* ! MIN */ +#include +#include +#include +#include +#include +#include +#include /* XXX: locking has to be checked before each stream of consecutive * ad_writes to prevent a lock in the middle from causing problems. @@ -47,48 +47,54 @@ ssize_t adf_pwrite(struct ad_fd *ad_fd, const void *buf, size_t count, off_t off } /* end is always 0 */ -ssize_t ad_write( ad, eid, off, end, buf, buflen ) - 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) { + EC_INIT; struct stat st; ssize_t cc; + off_t r_off; + + if (ad_data_fileno(ad) == AD_SYMLINK) { + errno = EACCES; + return -1; + } + + LOG(log_debug, logtype_ad, "ad_write: off: %ju, size: %zu, eabuflen: %zu", + (uintmax_t)off, buflen, ad->ad_rlen); 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); + 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_reso_fileno(ad), &st ) < 0) + return(-1); + off = st.st_size - off - ad_getentryoff(ad, eid); } - if ( ad->ad_rlen < r_off + cc ) { - ad->ad_rlen = r_off + cc; + if (ad->ad_vers == AD_VERSION_EA) { +#ifdef HAVE_EAFD + r_off = off; +#else + r_off = ADEDOFF_RFORK_OSX + off; +#endif + } else { + r_off = ad_getentryoff(ad, eid) + off; } - } - else { + cc = adf_pwrite(&ad->ad_resource_fork, buf, buflen, r_off); + + if ( ad->ad_rlen < off + cc ) + ad->ad_rlen = off + cc; + } else { return -1; /* we don't know how to write if it's not a ressource or data fork */ } + + if (ret != 0) + return ret; return( cc ); } @@ -151,25 +157,128 @@ char c = 0; } /* ------------------------ */ -int ad_rtruncate( ad, size ) - struct adouble *ad; - const off_t size; +int ad_rtruncate(struct adouble *ad, const char *uname, const off_t size) +{ + EC_INIT; + + /* + * We can't delete 0 byte size resource forks either, because a + * fork may reference the adouble handle with an open fd for the + * file, which means we would only delete the directory entry, not + * the file. Subsequently all code that works with fork handles + * finds the fork open, so eg flushing a fork (ad_flush()) will + * recreate ._ files. The correct place to delete 0 byte sized + * resource forks is in of_closefork(). + */ + + EC_NEG1( sys_ftruncate(ad_reso_fileno(ad), size + ad->ad_eid[ ADEID_RFORK ].ade_off) ); + + ad->ad_rlen = size; + +EC_CLEANUP: + if (ret != 0) + LOG(log_error, logtype_ad, "ad_rtruncate(\"%s\"): %s", + fullpathname(uname), strerror(errno)); + EC_EXIT; +} + +int ad_dtruncate(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 (sys_ftruncate(ad_data_fileno(ad), size) < 0) { + LOG(log_error, logtype_ad, "sys_ftruncate(fd: %d): %s", + ad_data_fileno(ad), strerror(errno)); + return -1; } - ad->ad_rlen = size; return 0; } -int ad_dtruncate(ad, size) - struct adouble *ad; - const off_t size; +/* ----------------------- */ +static int copy_all(const int dfd, const void *buf, + size_t buflen) { - if (sys_ftruncate(ad_data_fileno(ad), size) < 0) { - return -1; + ssize_t cc; + + while (buflen > 0) { + if ((cc = write(dfd, buf, buflen)) < 0) { + switch (errno) { + case EINTR: + continue; + default: + return -1; + } + } + buflen -= cc; } + return 0; } + +/* -------------------------- + * copy only the fork data stream +*/ +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; +}