Beispiel #1
0
/* rebuild the adouble header
 * XXX should be in a separate file ?
 */
int  ad_rebuild_adouble_header(struct adouble *ad)
{
    u_int32_t       eid;
    u_int32_t       temp;

    u_int16_t       nent;
    char        *buf, *nentp;

    /*
     * Rebuild any header information that might have changed.
     */
    buf = ad->ad_data;

    temp = htonl( ad->ad_magic );
    memcpy(buf, &temp, sizeof( temp ));
    buf += sizeof( temp );

    temp = htonl( ad->ad_version );
    memcpy(buf, &temp, sizeof( temp ));
    buf += sizeof( temp );

    memcpy(buf, ad->ad_filler, sizeof( ad->ad_filler ));
    buf += sizeof( ad->ad_filler );

    nentp = buf;
    buf += sizeof( nent );
    for ( eid = 0, nent = 0; eid < ADEID_MAX; eid++ ) {
        if ( ad->ad_eid[ eid ].ade_off == 0 ) {
            continue;
        }
        temp = htonl( EID_DISK(eid) );
        memcpy(buf, &temp, sizeof( temp ));
        buf += sizeof( temp );

        temp = htonl( ad->ad_eid[ eid ].ade_off );
        memcpy(buf, &temp, sizeof( temp ));
        buf += sizeof( temp );

        temp = htonl( ad->ad_eid[ eid ].ade_len );
        memcpy(buf, &temp, sizeof( temp ));
        buf += sizeof( temp );
        nent++;
    }
    nent = htons( nent );
    memcpy(nentp, &nent, sizeof( nent ));
    return ad_getentryoff(ad, ADEID_RFORK);
}
Beispiel #2
0
/* ------------------------------- */
int ad_readfile_init(const struct adouble *ad, 
				       const int eid, off_t *off,
				       const int end)
{
  int fd;

  if (end) 
    *off = ad_size(ad, eid) - *off;

  if (eid == ADEID_DFORK) {
    fd = ad_data_fileno(ad);
  } else {
    *off += ad_getentryoff(ad, eid);
    fd = ad_reso_fileno(ad);
  }

  return fd;
}
Beispiel #3
0
static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struct vol *vol)
{
    EC_INIT;
    struct adouble adv2;
    struct adouble adea;
    const char *adpath;
    int adflags;
    uint32_t ctime, mtime, afpinfo = 0;
    char *emptyad;

    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): BEGIN", fullpathname(path));

    ad_init(&adea, vol);
    ad_init_old(&adv2, AD_VERSION2, adea.ad_options);
    adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0;

    /* Open and lock adouble:v2 file */
    EC_ZERO( ad_open(&adv2, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR) );

    EC_NEG1_LOG( ad_tmplock(&adv2, ADEID_RFORK, ADLOCK_WR | ADLOCK_FILELOCK, 0, 0, 0) );
    EC_NEG1_LOG( adv2.ad_ops->ad_header_read(path, &adv2, sp) );

    /* Check if it's a non-empty header */
    if (S_ISREG(sp->st_mode))
        emptyad = &emptyfilad[0];
    else
        emptyad = &emptydirad[0];

    if (ad_getentrylen(&adv2, ADEID_COMMENT) != 0)
        goto copy;
    if (ad_getentryoff(&adv2, ADEID_FINDERI)
        && (ad_getentrylen(&adv2, ADEID_FINDERI) == ADEDLEN_FINDERI)
        && (memcmp(ad_entry(&adv2, ADEID_FINDERI), emptyad, ADEDLEN_FINDERI) != 0))
        goto copy;
    if (ad_getentryoff(&adv2, ADEID_FILEDATESI)) {
        EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_CREATE | AD_DATE_UNIX, &ctime) );
        EC_ZERO_LOG( ad_getdate(&adv2, AD_DATE_MODIFY | AD_DATE_UNIX, &mtime) );
        if ((ctime != mtime) || (mtime != sp->st_mtime))
            goto copy;
    }
    if (ad_getentryoff(&adv2, ADEID_AFPFILEI)) {
        if (memcmp(ad_entry(&adv2, ADEID_AFPFILEI), &afpinfo, ADEDLEN_AFPFILEI) != 0)
            goto copy;
    }

    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): default adouble", fullpathname(path), ret);
    goto EC_CLEANUP;

copy:
    /* Create a adouble:ea meta EA */
    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): copying adouble", fullpathname(path), ret);
    EC_ZERO_LOGSTR( ad_open(&adea, path, adflags | ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE),
                    "ad_conv_v22ea_hf(\"%s\"): error creating metadata EA: %s",
                    fullpathname(path), strerror(errno));
    EC_ZERO_LOG( ad_copy_header(&adea, &adv2) );
    ad_flush(&adea);

EC_CLEANUP:
    EC_ZERO_LOG( ad_close(&adv2, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
    EC_ZERO_LOG( ad_close(&adea, ADFLAGS_HF | ADFLAGS_SETSHRMD) );
    LOG(log_debug, logtype_default,"ad_conv_v22ea_hf(\"%s\"): END: %d", fullpathname(path), ret);
    EC_EXIT;
}
Beispiel #4
0
int ad_tmplock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len, int fork)
{
    struct flock lock;
    struct ad_fd *adf;
    int err;
    int type;

    LOG(log_debug, logtype_default, "ad_tmplock(%s, %s, off: %jd (%s), len: %jd): BEGIN",
        eid == ADEID_DFORK ? "data" : "reso",
        locktypetostr(locktype),
        (intmax_t)off,
        shmdstrfromoff(off),
        (intmax_t)len);

    lock.l_start = off;
    type = locktype;

    if (eid == ADEID_DFORK) {
        adf = &ad->ad_data_fork;
    } else {
        adf = &ad->ad_resource_fork;
        if (adf->adf_fd == -1) {
            /* there's no resource fork. return success */
            err = 0;
            goto exit;
        }
        /* if ADLOCK_FILELOCK we want a lock from offset 0
         * it's used when deleting a file:
         * in open we put read locks on meta datas
         * in delete a write locks on the whole file
         * so if the file is open by somebody else it fails
         */
        if (!(type & ADLOCK_FILELOCK))
            lock.l_start += ad_getentryoff(ad, eid);
    }

    if (!(adf->adf_flags & O_RDWR) && (type & ADLOCK_WR)) {
        type = (type & ~ADLOCK_WR) | ADLOCK_RD;
    }

    lock.l_type = XLATE_FCNTL_LOCK(type & ADLOCK_MASK);
    lock.l_whence = SEEK_SET;
    lock.l_len = len;

    /* see if it's locked by another fork. */
    if (fork && adf_findxlock(adf, fork,
                              ADLOCK_WR | ((type & ADLOCK_WR) ? ADLOCK_RD : 0),
                              lock.l_start, lock.l_len) > -1) {
        errno = EACCES;
        err = -1;
        goto exit;
    }

    /* okay, we might have ranges byte-locked. we need to make sure that
     * we restore the appropriate ranges once we're done. so, we check
     * for overlap on an unlock and relock.
     * XXX: in the future, all the byte locks will be sorted and contiguous.
     *      we just want to upgrade all the locks and then downgrade them
     *      here. */
    err = set_lock(adf->adf_fd, F_SETLK, &lock);
    if (!err && (lock.l_type == F_UNLCK))
        adf_relockrange(adf, adf->adf_fd, lock.l_start, len);

exit:
    LOG(log_debug, logtype_default, "ad_tmplock: END: %d", err);
    return err;
}
Beispiel #5
0
int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len, int fork)
{
    struct flock lock;
    struct ad_fd *adf;
    adf_lock_t *adflock;
    int oldlock;
    int i;
    int type;
    int ret = 0, fcntl_lock_err = 0;

    LOG(log_debug, logtype_default, "ad_lock(%s, %s, off: %jd (%s), len: %jd): BEGIN",
        eid == ADEID_DFORK ? "data" : "reso",
        locktypetostr(locktype),
        (intmax_t)off,
        shmdstrfromoff(off),
        (intmax_t)len);

    if ((locktype & ADLOCK_FILELOCK) && (len != 1))
        AFP_PANIC("lock API error");

    type = locktype;

    if (eid == ADEID_DFORK) {
        adf = &ad->ad_data_fork;
        lock.l_start = off;
    } else { /* rfork */
        if (type & ADLOCK_FILELOCK) {
            adf = &ad->ad_data_fork;
            lock.l_start = rf2off(off);
        } else {
            adf = ad->ad_rfp;
            lock.l_start = off + ad_getentryoff(ad, ADEID_RFORK);
        }
    }

    /* NOTE: we can't write lock a read-only file. on those, we just
     * make sure that we have a read lock set. that way, we at least prevent
     * someone else from really setting a deny read/write on the file.
     */
    if (!(adf->adf_flags & O_RDWR) && (type & ADLOCK_WR)) {
        type = (type & ~ADLOCK_WR) | ADLOCK_RD;
    }

    lock.l_type = XLATE_FCNTL_LOCK(type & ADLOCK_MASK);
    lock.l_whence = SEEK_SET;
    lock.l_len = len;

    /* byte_lock(len=-1) lock whole file */
    if (len == BYTELOCK_MAX) {
        lock.l_len -= lock.l_start; /* otherwise  EOVERFLOW error */
    }

    /* see if it's locked by another fork.
     * NOTE: this guarantees that any existing locks must be at most
     * read locks. we use ADLOCK_WR/RD because F_RD/WRLCK aren't
     * guaranteed to be ORable. */
    if (adf_findxlock(adf, fork, ADLOCK_WR |
                      ((type & ADLOCK_WR) ? ADLOCK_RD : 0),
                      lock.l_start, lock.l_len) > -1) {
        errno = EACCES;
        ret = -1;
        goto exit;
    }

    /* look for any existing lock that we may have */
    i = adf_findlock(adf, fork, ADLOCK_RD | ADLOCK_WR, lock.l_start, lock.l_len);
    adflock = (i < 0) ? NULL : adf->adf_lock + i;

    /* here's what we check for:
       1) we're trying to re-lock a lock, but we didn't specify an update.
       2) we're trying to free only part of a lock.
       3) we're trying to free a non-existent lock. */
    if ( (!adflock && (lock.l_type == F_UNLCK))
            ||
            (adflock
             && !(type & ADLOCK_UPGRADE)
             && ((lock.l_type != F_UNLCK)
                 || (adflock->lock.l_start != lock.l_start)
                 || (adflock->lock.l_len != lock.l_len) ))
       ) {
        errno = EINVAL;
        ret = -1;
        goto exit;
    }


    /* now, update our list of locks */
    /* clear the lock */
    if (lock.l_type == F_UNLCK) {
        adf_freelock(adf, i);
        goto exit;
    }

    /* attempt to lock the file. */
    if (set_lock(adf->adf_fd, F_SETLK, &lock) < 0) {
        ret = -1;
        goto exit;
    }

    /* we upgraded this lock. */
    if (adflock && (type & ADLOCK_UPGRADE)) {
        memcpy(&adflock->lock, &lock, sizeof(lock));
        goto exit;
    }

    /* it wasn't an upgrade */
    oldlock = -1;
    if (lock.l_type == F_RDLCK) {
        oldlock = adf_findxlock(adf, fork, ADLOCK_RD, lock.l_start, lock.l_len);
    }

    /* no more space. this will also happen if lockmax == lockcount == 0 */
    if (adf->adf_lockmax == adf->adf_lockcount) {
        adf_lock_t *tmp = (adf_lock_t *)
                          realloc(adf->adf_lock, sizeof(adf_lock_t)*
                                  (adf->adf_lockmax + ARRAY_BLOCK_SIZE));
        if (!tmp) {
            ret = fcntl_lock_err = -1;
            goto exit;
        }
        adf->adf_lock = tmp;
        adf->adf_lockmax += ARRAY_BLOCK_SIZE;
    }
    adflock = adf->adf_lock + adf->adf_lockcount;

    /* fill in fields */
    memcpy(&adflock->lock, &lock, sizeof(lock));
    adflock->user = fork;
    if (oldlock > -1) {
        adflock->refcount = (adf->adf_lock + oldlock)->refcount;
    } else if ((adflock->refcount = calloc(1, sizeof(int))) == NULL) {
        ret = fcntl_lock_err = 1;
        goto exit;
    }

    (*adflock->refcount)++;
    adf->adf_lockcount++;

exit:
    if (ret != 0) {
        if (fcntl_lock_err != 0) {
            lock.l_type = F_UNLCK;
            set_lock(adf->adf_fd, F_SETLK, &lock);
        }
    }
    LOG(log_debug, logtype_default, "ad_lock: END: %d", ret);
    return ret;
}