X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Ffork.c;h=a77c6adcad5d826c54bc457f4b01ac1111798c1a;hp=38acf64bc5587a73f67c3d599c7e2f1c3c947d32;hb=2d4c0bd1e9b0ad0db32e4f3705fe67f657f57230;hpb=8fa8b4113c25b47937ddf7cadf64f060d79c2ef5 diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 38acf64b..a77c6adc 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -165,7 +166,7 @@ static int fork_setmode(const AFPObj *obj, struct adouble *adp, int eid, int acc int fd = (eid == ADEID_DFORK) ? ad_data_fileno(adp) : ad_reso_fileno(adp); - if (fd != -1 && fd != -2 && fcntl(fd, F_SHARE, &shmd) != 0) { + if (fd != -1 && fd != AD_SYMLINK && fcntl(fd, F_SHARE, &shmd) != 0) { LOG(log_debug, logtype_afpd, "fork_setmode: fcntl: %s", strerror(errno)); errno = EACCES; return -1; @@ -250,7 +251,6 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si struct stat *st; uint16_t bshort; struct path *s_path; - struct stat xxx; ibuf++; fork = *ibuf++; @@ -301,8 +301,11 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si LOG(log_error, logtype_afpd, "afp_openfork(%s): %s", s_path->m_name, strerror(errno)); return AFPERR_PARAM; } - /* FIXME should we check it first ? */ + upath = s_path->u_name; + path = s_path->m_name; + st = &s_path->st; + if (!vol_unix_priv(vol)) { if (check_access(obj, vol, upath, access ) < 0) { return AFPERR_ACCESS; @@ -313,124 +316,105 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si } } - st = &s_path->st; - /* 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 - ad_open so that we can keep file locks together. - FIXME: add the fork we are opening? - */ - if ((opened = of_findname(s_path))) { + if ((opened = of_findname(vol, s_path))) { adsame = opened->of_ad; } - if ( fork == OPENFORK_DATA ) { + adflags = ADFLAGS_SETSHRMD; + + if (fork == OPENFORK_DATA) { eid = ADEID_DFORK; - adflags = ADFLAGS_DF | ADFLAGS_HF | ADFLAGS_NOHF; + adflags |= ADFLAGS_DF; } else { eid = ADEID_RFORK; - adflags = ADFLAGS_RF | ADFLAGS_HF | ADFLAGS_NOHF; - if (!(access & OPENACC_WR)) - adflags |= ADFLAGS_NORF; + adflags |= ADFLAGS_RF; } - path = s_path->m_name; - if (( ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, - adsame, st)) == NULL ) { - return( AFPERR_NFILE ); + if (access & OPENACC_WR) { + adflags |= ADFLAGS_RDWR; + if (fork != OPENFORK_DATA) + /* + * We only try to create the resource + * fork if the user wants to open it for write acess. + */ + adflags |= ADFLAGS_CREATE; + } else { + adflags |= ADFLAGS_RDONLY; } + if ((ofork = of_alloc(vol, curdir, path, &ofrefnum, eid, adsame, st)) == NULL) + return AFPERR_NFILE; + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\", %s, %s)", fullpathname(s_path->u_name), (fork == OPENFORK_DATA) ? "data" : "reso", !(access & OPENACC_WR) ? "O_RDONLY" : "O_RDWR"); ret = AFPERR_NOOBJ; + + /* First ad_open(), opens data or ressource fork */ + if (ad_open(ofork->of_ad, upath, adflags, 0666) < 0) { + switch (errno) { + case EROFS: + ret = AFPERR_VLOCK; + case EACCES: + goto openfork_err; + case ENOENT: + goto openfork_err; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + ret = AFPERR_PARAM; + goto openfork_err; + } + } + + /* + * Create metadata if we open rw, otherwise only open existing metadata + */ if (access & OPENACC_WR) { - /* try opening in read-write mode */ - if (ad_open(ofork->of_ad, upath, - adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) { - switch ( errno ) { - case EROFS: - ret = AFPERR_VLOCK; - case EACCES: - goto openfork_err; - case ENOENT: - if (fork == OPENFORK_DATA) { - /* try to open only the data fork */ - if (ad_open(ofork->of_ad, upath, - ADFLAGS_DF | ADFLAGS_RDWR | ADFLAGS_SETSHRMD) < 0) { - goto openfork_err; - } - adflags = ADFLAGS_DF; - } 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(ofork->of_ad, upath, - adflags | ADFLAGS_RDWR | ADFLAGS_SETSHRMD | ADFLAGS_CREATE, 0666) < 0) - goto openfork_err; - ofork->of_flags |= AFPFORK_META; - } - break; - case EMFILE : - case ENFILE : - ret = AFPERR_NFILE; - goto openfork_err; - case EISDIR : - ret = AFPERR_BADTYPE; - goto openfork_err; - default: - LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); - ret = AFPERR_PARAM; + adflags = ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE; + } else { + adflags = ADFLAGS_HF | ADFLAGS_RDONLY; + } + + if (ad_open(ofork->of_ad, upath, adflags, 0666) == 0) { + ofork->of_flags |= AFPFORK_META; + if (ad_get_MD_flags(ofork->of_ad) & O_CREAT) { + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): setting CNID", upath); + cnid_t id; + if ((id = get_id(vol, ofork->of_ad, st, dir->d_did, upath, strlen(upath))) == CNID_INVALID) { + LOG(log_error, logtype_afpd, "afp_createfile(\"%s\"): CNID error", upath); goto openfork_err; } - } - else { - /* the ressource fork is open too */ - ofork->of_flags |= AFPFORK_META; + (void)ad_setid(ofork->of_ad, st->st_dev, st->st_ino, id, dir->d_did, vol->v_stamp); + ad_flush(ofork->of_ad); } } else { - /* try opening in read-only mode */ - ret = AFPERR_NOOBJ; - if (ad_open(ofork->of_ad, upath, adflags | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) { - switch ( errno ) { - case EROFS: - ret = AFPERR_VLOCK; - goto openfork_err; - case EACCES: - goto openfork_err; - case ENOENT: - /* see if client asked for a read only data fork */ - if (fork == OPENFORK_DATA) { - if (ad_open(ofork->of_ad, upath, ADFLAGS_DF | ADFLAGS_RDONLY | ADFLAGS_SETSHRMD) < 0) { - goto openfork_err; - } - adflags = ADFLAGS_DF; - } - /* else we don't set AFPFORK_META because there's no ressource fork file - * We need to check AFPFORK_META 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 : - ret = AFPERR_NFILE; - goto openfork_err; - case EISDIR : - ret = AFPERR_BADTYPE; - goto openfork_err; - default: - LOG(log_error, logtype_afpd, "afp_openfork(\"%s\"): %s", - fullpathname(s_path->m_name), strerror(errno) ); - goto openfork_err; - } - } else { - ofork->of_flags |= AFPFORK_META; + switch (errno) { + case EACCES: + case ENOENT: + /* no metadata? We don't care! */ + break; + case EROFS: + ret = AFPERR_VLOCK; + case EMFILE : + case ENFILE : + ret = AFPERR_NFILE; + goto openfork_err; + case EISDIR : + ret = AFPERR_BADTYPE; + goto openfork_err; + default: + LOG(log_error, logtype_afpd, "afp_openfork(%s): ad_open: %s", s_path->m_name, strerror(errno) ); + ret = AFPERR_PARAM; + goto openfork_err; } } @@ -500,6 +484,9 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si if ((access & OPENACC_RD)) ofork->of_flags |= AFPFORK_ACCRD; + LOG(log_debug, logtype_afpd, "afp_openfork(\"%s\"): fork: %" PRIu16, + fullpathname(s_path->m_name), ofork->of_refnum); + memcpy(rbuf, &ofrefnum, sizeof(ofrefnum)); return( AFP_OK ); @@ -596,7 +583,7 @@ int afp_setforkparams(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf _U_, s goto afp_setfork_err; } - err = ad_rtruncate(ofork->of_ad, size); + err = ad_rtruncate(ofork->of_ad, mtoupath(ofork->of_vol, of_name(ofork), ofork->of_did, utf8_encoding(obj)), size); if (st_size > size) ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, size, st_size -size, ofork->of_refnum); if (err < 0) @@ -630,6 +617,7 @@ afp_setfork_err: case EDQUOT: case EFBIG: case ENOSPC: + LOG(log_error, logtype_afpd, "afp_setforkparams: DISK FULL"); return AFPERR_DFULL; default: return AFPERR_PARAM; @@ -753,8 +741,6 @@ int afp_bytelock_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t static int read_file(const struct ofork *ofork, int eid, off_t offset, char *rbuf, size_t *rbuflen) { ssize_t cc; - int eof = 0; - char *p, *q; cc = ad_read(ofork->of_ad, eid, offset, rbuf, *rbuflen); if ( cc < 0 ) { @@ -773,7 +759,7 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si { DSI *dsi = obj->dsi; struct ofork *ofork; - off_t offset, saveoff, reqcount, savereqcount, size; + off_t offset, saveoff, reqcount, savereqcount; ssize_t cc, err; int eid; uint16_t ofrefnum; @@ -807,65 +793,53 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si offset = get_off_t(&ibuf, is64); reqcount = get_off_t(&ibuf, is64); - /* reqcount isn't always truthful. we need to deal with that. */ - size = ad_size(ofork->of_ad, eid); + /* zero request count */ + err = AFP_OK; + if (!reqcount) { + goto afp_read_err; + } - LOG(log_debug, logtype_afpd, - "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s, size: %" PRIu64 ")", - offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r", size); + AFP_READ_START((long)reqcount); - /* subtract off the offset */ - if (reqcount + offset > size) { - reqcount = size - offset; - err = AFPERR_EOF; - } + LOG(log_debug, logtype_afpd, + "afp_read(fork: %" PRIu16 " [%s], off: %" PRIu64 ", len: %" PRIu64 ")", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount); savereqcount = reqcount; saveoff = offset; - LOG(log_debug, logtype_afpd, - "afp_read(off: %" PRIu64 ", len: %" PRIu64 ", fork: %s)", - offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); - if (reqcount < 0 || offset < 0) { err = AFPERR_PARAM; goto afp_read_err; } - /* zero request count */ - err = AFP_OK; - if (!reqcount) { - goto afp_read_err; + if (obj->options.flags & OPTION_AFP_READ_LOCK) { + if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) { + err = AFPERR_LOCK; + goto afp_read_err; + } } - LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd)", - of_name(ofork), (intmax_t)offset, (intmax_t)reqcount); - - if (obj->options.flags & OPTION_AFP_READ_LOCK) { - if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, offset, reqcount, ofork->of_refnum) < 0) { - err = AFPERR_LOCK; - goto afp_read_err; - } - } - #ifdef WITH_SENDFILE - if (!(obj->options.flags & OPTION_NOSENDFILE)) { + if (!(eid == ADEID_DFORK && ad_data_fileno(ofork->of_ad) == AD_SYMLINK) && + !(obj->options.flags & OPTION_NOSENDFILE)) { int fd = ad_readfile_init(ofork->of_ad, eid, &offset, 0); if (dsi_stream_read_file(dsi, fd, offset, reqcount, err) < 0) { LOG(log_error, logtype_afpd, "afp_read(%s): ad_readfile: %s", of_name(ofork), strerror(errno)); goto afp_read_exit; } - dsi_readdone(dsi); goto afp_read_done; } #endif - *rbuflen = MIN(reqcount, *rbuflen); + *rbuflen = MIN(reqcount, dsi->server_quantum); - err = read_file(ofork, eid, offset, rbuf, rbuflen); - if (err < 0) + cc = read_file(ofork, eid, offset, ibuf, rbuflen); + if (cc < 0) { + err = cc; goto afp_read_done; + } LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file", @@ -878,18 +852,22 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si * we know that we're sending some data. if we fail, something * horrible happened. */ - if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) + if ((cc = dsi_readinit(dsi, ibuf, *rbuflen, reqcount, err)) < 0) goto afp_read_exit; *rbuflen = cc; while (*rbuflen > 0) { - cc = read_file(ofork, eid, offset, rbuf, rbuflen); + /* + * This loop isn't really entered anymore, we've already + * sent the whole requested block in dsi_readinit(). + */ + cc = read_file(ofork, eid, offset, ibuf, rbuflen); if (cc < 0) goto afp_read_exit; offset += *rbuflen; /* dsi_read() also returns buffer size of next allocation */ - cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */ + cc = dsi_read(dsi, ibuf, *rbuflen); /* send it off */ if (cc < 0) goto afp_read_exit; *rbuflen = cc; @@ -907,6 +885,8 @@ afp_read_exit: afp_read_done: if (obj->options.flags & OPTION_AFP_READ_LOCK) ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum); + + AFP_READ_DONE(); return err; afp_read_err: @@ -1057,11 +1037,11 @@ int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, s return( AFPERR_PARAM ); } - LOG(log_debug, logtype_afpd, "afp_closefork(fork: %s)", - (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); + LOG(log_debug, logtype_afpd, "afp_closefork(fork: %" PRIu16 " [%s])", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "rsrc"); if (of_closefork(obj, ofork) < 0 ) { - LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) ); + LOG(log_error, logtype_afpd, "afp_closefork: of_closefork: %s", strerror(errno) ); return( AFPERR_PARAM ); } @@ -1073,7 +1053,6 @@ static ssize_t write_file(struct ofork *ofork, int eid, off_t offset, char *rbuf, size_t rbuflen) { - char *p, *q; ssize_t cc; LOG(log_debug, logtype_afpd, "write_file(off: %ju, size: %zu)", @@ -1085,6 +1064,7 @@ static ssize_t write_file(struct ofork *ofork, int eid, case EDQUOT : case EFBIG : case ENOSPC : + LOG(log_error, logtype_afpd, "write_file: DISK FULL"); return( AFPERR_DFULL ); case EACCES: return AFPERR_ACCESS; @@ -1098,16 +1078,21 @@ static ssize_t write_file(struct ofork *ofork, int eid, } -/* FPWrite. NOTE: on an error, we always use afp_write_err as +/* + * 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 - * in reqcount et al. */ + * 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, oldsize, newsize; + off_t offset, saveoff, reqcount, oldsize, newsize; int endflag, eid, err = AFP_OK; - uint16_t ofrefnum; - ssize_t cc; + uint16_t ofrefnum; + ssize_t cc; + DSI *dsi = obj->dsi; + char *rcvbuf = (char *)dsi->commands; + size_t rcvbuflen = dsi->server_quantum; /* figure out parameters */ ibuf++; @@ -1125,8 +1110,8 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s goto afp_write_err; } - LOG(log_debug, logtype_afpd, "afp_write(off: %" PRIu64 ", size: %" PRIu64 ", fork: %s)", - offset, reqcount, (ofork->of_flags & AFPFORK_DATA) ? "d" : "r"); + LOG(log_debug, logtype_afpd, "afp_write(fork: %" PRIu16 " [%s], off: %" PRIu64 ", size: %" PRIu64 ")", + ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount); if ((ofork->of_flags & AFPFORK_ACCWR) == 0) { err = AFPERR_ACCESS; @@ -1161,6 +1146,7 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s /* offset can overflow on 64-bit capable filesystems. * report disk full if that's going to happen. */ if (sum_neg(is64, offset, reqcount)) { + LOG(log_error, logtype_afpd, "write_fork: DISK FULL"); err = AFPERR_DFULL; goto afp_write_err; } @@ -1171,29 +1157,31 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s goto afp_write_err; } + AFP_WRITE_START((long)reqcount); + saveoff = offset; - if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, - reqcount, ofork->of_refnum) < 0) { - err = AFPERR_LOCK; - goto afp_write_err; + if (obj->options.flags & OPTION_AFP_READ_LOCK) { + if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, reqcount, ofork->of_refnum) < 0) { + err = AFPERR_LOCK; + goto afp_write_err; + } } - DSI *dsi = obj->dsi; - /* find out what we have already and write it out. */ - cc = dsi_writeinit(dsi, rbuf, *rbuflen); + /* find out what we have already */ + cc = dsi_writeinit(dsi, rcvbuf, rcvbuflen); - if (!cc || (cc = write_file(ofork, eid, offset, rbuf, cc)) < 0) { + if (!cc || (cc = write_file(ofork, eid, offset, rcvbuf, cc)) < 0) { dsi_writeflush(dsi); *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); return cc; } offset += cc; #if 0 /*def HAVE_SENDFILE_WRITE*/ - if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket, - offset, dsi->datasize)) < 0) { + if ((cc = ad_writefile(ofork->of_ad, eid, dsi->socket, offset, dsi->datasize)) < 0) { switch (errno) { case EDQUOT: case EFBIG: @@ -1206,8 +1194,8 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s } dsi_writeflush(dsi); *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, - reqcount, ofork->of_refnum); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); return cc; } @@ -1217,18 +1205,24 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s /* 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)) < 0) { + while ((cc = dsi_write(dsi, rcvbuf, rcvbuflen))) { + + if ((cc = write_file(ofork, eid, offset, rcvbuf, cc)) < 0) { dsi_writeflush(dsi); *rbuflen = 0; - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, - reqcount, ofork->of_refnum); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); return cc; } + + LOG(log_debug, logtype_afpd, "afp_write: wrote: %jd, offset: %jd", + (intmax_t)cc, (intmax_t)offset); + offset += cc; } - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); + if (obj->options.flags & OPTION_AFP_READ_LOCK) + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount, ofork->of_refnum); if ( ad_meta_fileno( ofork->of_ad ) != -1 ) /* META */ ofork->of_flags |= AFPFORK_DIRTY; @@ -1239,11 +1233,12 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0; *rbuflen = set_off_t (offset, rbuf, is64); + AFP_WRITE_DONE(); return( AFP_OK ); afp_write_err: - dsi_writeinit(obj->dsi, rbuf, *rbuflen); - dsi_writeflush(obj->dsi); + dsi_writeinit(dsi, rcvbuf, rcvbuflen); + dsi_writeflush(dsi); if (err != AFP_OK) { *rbuflen = 0;