From: jmarcus Date: Sun, 3 Feb 2002 04:57:38 +0000 (+0000) Subject: Fix a race condition on reading and writing data to the same fork. Also, X-Git-Tag: point-backport-1-5-2~68 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=5ed735048bdad03ba5d0d5302c3fb5b75b07a2a4 Fix a race condition on reading and writing data to the same fork. Also, correct a lock contention issue where one afpd process could lock a byte region, and then only unlock part of that region. The next afpd process to access the same reason would receive AFPERR_LOCK. Submitted by didier . --- diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 291972d0..dc64e90f 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -1,5 +1,5 @@ /* - * $Id: fork.c,v 1.20 2002-02-02 19:11:34 jmarcus Exp $ + * $Id: fork.c,v 1.21 2002-02-03 04:57:38 jmarcus Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -790,8 +790,8 @@ int ibuflen, *rbuflen; { struct ofork *ofork; off_t size; - int32_t offset, saveoff, reqcount; - int cc, err, eid, xlate = 0; + int32_t offset, saveoff, reqcount, savereqcount; + int cc, err, saveerr, eid, xlate = 0; u_int16_t ofrefnum; u_char nlmask, nlchar; @@ -839,42 +839,50 @@ int ibuflen, *rbuflen; } /* zero request count */ + err = AFP_OK; if (!reqcount) { - err = AFP_OK; goto afp_read_err; } /* reqcount isn't always truthful. we need to deal with that. */ - if ((size = ad_size(ofork->of_ad, eid)) == 0) { + size = ad_size(ofork->of_ad, eid); + + if (offset >= size) { err = AFPERR_EOF; goto afp_read_err; } + /* subtract off the offset */ + size -= offset; + savereqcount = reqcount; + if (reqcount > size) { + reqcount = size; + err = AFPERR_EOF; + } + saveoff = offset; - if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, reqcount) < 0) { + /* if EOF lock on the old reqcount, some prg may need it */ + if (ad_tmplock(ofork->of_ad, eid, ADLOCK_RD, saveoff, savereqcount) < 0) { err = AFPERR_LOCK; goto afp_read_err; } #define min(a,b) ((a)<(b)?(a):(b)) *rbuflen = min( reqcount, *rbuflen ); + saveerr = err; err = read_file(ofork, eid, offset, nlmask, nlchar, rbuf, rbuflen, xlate); if (err < 0) goto afp_read_done; - + if (saveerr < 0) { + err = saveerr; + goto afp_read_done; + } /* dsi can stream requests. we can only do this if we're not checking * for an end-of-line character. oh well. */ if ((obj->proto == AFPPROTO_DSI) && (*rbuflen < reqcount) && !nlmask) { DSI *dsi = obj->handle; - /* subtract off the offset */ - size -= offset; - if (reqcount > size) { - reqcount = size; - err = AFPERR_EOF; - } - if (obj->options.flags & OPTION_DEBUG) { printf( "(read) reply: %d/%d, %d\n", *rbuflen, reqcount, dsi->clientID); @@ -935,12 +943,12 @@ afp_read_loop: afp_read_exit: LOG(log_error, logtype_default, "afp_read: %s", strerror(errno)); dsi_readdone(dsi); - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount); + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount); obj->exit(1); } afp_read_done: - ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, reqcount); + ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount); return err; afp_read_err: