⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lock.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 3 页
字号:
	}
	else {
	    memcpy(ptr, dp->owner, strlen(dp->owner) + 1);	
	    ptr += strlen(dp->owner) + 1;
	}
	if (dp->auth_user == NULL) {
            *ptr++ = '\0';
	}
	else {
	    memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1);
	    ptr += strlen(dp->auth_user) + 1;
	}

	dp = dp->next;
    }

    while(ip) {
	*ptr++ = DAV_LOCK_INDIRECT;	/* Indirect lock prefix */
	memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken));	/* Locktoken */
	ptr += sizeof(*ip->locktoken);
	memcpy(ptr, &ip->timeout, sizeof(ip->timeout));		/* Expire time */
	ptr += sizeof(ip->timeout);
	memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize));	/* Size of key */
	ptr += sizeof(ip->key.dsize);
	memcpy(ptr, ip->key.dptr, ip->key.dsize);	/* Key data */
	ptr += ip->key.dsize;
	ip = ip->next;
    }

    if ((err = dav_dbm_store(lockdb->info->db, key, val)) != NULL) {
	/* ### more details? add an error_id? */
	return dav_push_error(lockdb->info->pool,
			      HTTP_INTERNAL_SERVER_ERROR,
			      DAV_ERR_LOCK_SAVE_LOCK,
			      "Could not save lock information.",
			      err);
    }

    return NULL;
}

/*
** dav_load_lock_record:  Reads lock information about key from lock db;
**    creates linked lists of the direct and indirect locks.
**
**    If add_method = DAV_APPEND_LIST, the result will be appended to the
**    head of the direct and indirect lists supplied.
**
**    Passive lock removal:  If lock has timed out, it will not be returned.
**    ### How much "logging" does RFC 2518 require?
*/
static dav_error * dav_fs_load_lock_record(dav_lockdb *lockdb, apr_datum_t key,
					   int add_method,
					   dav_lock_discovery **direct,
					   dav_lock_indirect **indirect)
{
    apr_pool_t *p = lockdb->info->pool;
    dav_error *err;
    apr_size_t offset = 0;
    int need_save = DAV_FALSE;
    apr_datum_t val = { 0 };
    dav_lock_discovery *dp;
    dav_lock_indirect *ip;
    dav_buffer buf = { 0 };

    if (add_method != DAV_APPEND_LIST) {
	*direct = NULL;
	*indirect = NULL;
    }

    if ((err = dav_fs_really_open_lockdb(lockdb)) != NULL) {
	/* ### add a higher-level error? */
	return err;
    }

    /*
    ** If we opened readonly and the db wasn't there, then there are no
    ** locks for this resource. Just exit.
    */
    if (lockdb->info->db == NULL)
	return NULL;

    if ((err = dav_dbm_fetch(lockdb->info->db, key, &val)) != NULL)
        return err;
	
    if (!val.dsize)
	return NULL;

    while (offset < val.dsize) {
	switch (*(val.dptr + offset++)) {
	case DAV_LOCK_DIRECT:
	    /* Create and fill a dav_lock_discovery structure */

	    dp = apr_pcalloc(p, sizeof(*dp));
	    memcpy(dp, val.dptr + offset, sizeof(dp->f));
	    offset += sizeof(dp->f);
            dp->locktoken = apr_palloc(p, sizeof(*dp->locktoken));
            memcpy(dp->locktoken, val.dptr + offset, sizeof(*dp->locktoken));
            offset += sizeof(*dp->locktoken);
	    if (*(val.dptr + offset) == '\0') {
		++offset;
	    }
	    else {
		dp->owner = apr_pstrdup(p, val.dptr + offset);
		offset += strlen(dp->owner) + 1;
	    }

            if (*(val.dptr + offset) == '\0') {
                ++offset;
            } 
            else {
                dp->auth_user = apr_pstrdup(p, val.dptr + offset);
                offset += strlen(dp->auth_user) + 1;
            }

	    if (!dav_fs_lock_expired(dp->f.timeout)) {
		dp->next = *direct;
		*direct = dp;
	    }
	    else {
		need_save = DAV_TRUE;

		/* Remove timed-out locknull fm .locknull list */
		if (*key.dptr == DAV_TYPE_FNAME) {
		    const char *fname = key.dptr + 1;
		    apr_finfo_t finfo;
                    apr_status_t rv;

		    /* if we don't see the file, then it's a locknull */
                    rv = apr_lstat(&finfo, fname, APR_FINFO_MIN, p);
		    if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
			if ((err = dav_fs_remove_locknull_member(p, fname, &buf)) != NULL) {
                            /* ### push a higher-level description? */
                            return err;
                        }
		    }
		}
	    }
	    break;

	case DAV_LOCK_INDIRECT:
	    /* Create and fill a dav_lock_indirect structure */

	    ip = apr_pcalloc(p, sizeof(*ip));
            ip->locktoken = apr_palloc(p, sizeof(*ip->locktoken));
	    memcpy(ip->locktoken, val.dptr + offset, sizeof(*ip->locktoken));
	    offset += sizeof(*ip->locktoken);
	    memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout));
	    offset += sizeof(ip->timeout);
            memcpy(&ip->key.dsize, val.dptr + offset, sizeof(ip->key.dsize)); /* length of datum */
	    offset += sizeof(ip->key.dsize);
	    ip->key.dptr = apr_palloc(p, ip->key.dsize); 
	    memcpy(ip->key.dptr, val.dptr + offset, ip->key.dsize);
	    offset += ip->key.dsize;

	    if (!dav_fs_lock_expired(ip->timeout)) {
		ip->next = *indirect;
		*indirect = ip;
	    }
	    else {
		need_save = DAV_TRUE;
		/* A locknull resource will never be locked indirectly */
	    }

	    break;

	default:
	    dav_dbm_freedatum(lockdb->info->db, val);

	    /* ### should use a computed_desc and insert corrupt token data */
	    --offset;
	    return dav_new_error(p,
				 HTTP_INTERNAL_SERVER_ERROR,
				 DAV_ERR_LOCK_CORRUPT_DB,
				 apr_psprintf(p,
					     "The lock database was found to "
					     "be corrupt. offset %"
                                             APR_SIZE_T_FMT ", c=%02x",
					     offset, val.dptr[offset]));
	}
    }

    dav_dbm_freedatum(lockdb->info->db, val);

    /* Clean up this record if we found expired locks */
    /*
    ** ### shouldn't do this if we've been opened READONLY. elide the
    ** ### timed-out locks from the response, but don't save that info back
    */
    if (need_save == DAV_TRUE) {
	return dav_fs_save_lock_record(lockdb, key, *direct, *indirect);
    }

    return NULL;
}

/* resolve <indirect>, returning <*direct> */
static dav_error * dav_fs_resolve(dav_lockdb *lockdb,
				  dav_lock_indirect *indirect,
				  dav_lock_discovery **direct,
				  dav_lock_discovery **ref_dp,
				  dav_lock_indirect **ref_ip)
{
    dav_error *err;
    dav_lock_discovery *dir;
    dav_lock_indirect *ind;
	
    if ((err = dav_fs_load_lock_record(lockdb, indirect->key,
				       DAV_CREATE_LIST,
				       &dir, &ind)) != NULL) {
	/* ### insert a higher-level description? */
	return err;
    }
    if (ref_dp != NULL) {
	*ref_dp = dir;
	*ref_ip = ind;
    }
		
    for (; dir != NULL; dir = dir->next) {
	if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) {
	    *direct = dir;
	    return NULL;
	}
    }

    /* No match found (but we should have found one!) */

    /* ### use a different description and/or error ID? */
    return dav_new_error(lockdb->info->pool,
			 HTTP_INTERNAL_SERVER_ERROR,
			 DAV_ERR_LOCK_CORRUPT_DB,
			 "The lock database was found to be corrupt. "
			 "An indirect lock's direct lock could not "
			 "be found.");
}

/* ---------------------------------------------------------------
**
** Property-related lock functions
**
*/

/*
** dav_fs_get_supportedlock:  Returns a static string for all supportedlock
**    properties. I think we save more returning a static string than
**    constructing it every time, though it might look cleaner.
*/
static const char *dav_fs_get_supportedlock(const dav_resource *resource)
{
    static const char supported[] = DEBUG_CR
	"<D:lockentry>" DEBUG_CR
	"<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR
	"<D:locktype><D:write/></D:locktype>" DEBUG_CR
	"</D:lockentry>" DEBUG_CR
	"<D:lockentry>" DEBUG_CR
	"<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR
	"<D:locktype><D:write/></D:locktype>" DEBUG_CR
	"</D:lockentry>" DEBUG_CR;

    return supported;
}

/* ---------------------------------------------------------------
**
** General lock functions
**
*/

/* ---------------------------------------------------------------
**
** Functions dealing with lock-null resources
**
*/

/*
** dav_fs_load_locknull_list:  Returns a dav_buffer dump of the locknull file
**    for the given directory.
*/
static dav_error * dav_fs_load_locknull_list(apr_pool_t *p, const char *dirpath,
					     dav_buffer *pbuf) 
{
    apr_finfo_t finfo;
    apr_file_t *file = NULL;
    dav_error *err = NULL;
    apr_size_t amt;
    apr_status_t rv;

    dav_buffer_init(p, pbuf, dirpath);

    if (pbuf->buf[pbuf->cur_len - 1] == '/')
	pbuf->buf[--pbuf->cur_len] = '\0';

    dav_buffer_place(p, pbuf, "/" DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE);

    /* reset this in case we leave w/o reading into the buffer */
    pbuf->cur_len = 0;

    if (apr_file_open(&file, pbuf->buf, APR_READ | APR_BINARY, APR_OS_DEFAULT,
                p) != APR_SUCCESS) {
	return NULL;
    }

    rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, file);
    if (rv != APR_SUCCESS) {
	err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			    apr_psprintf(p,
					"Opened but could not stat file %s",
					pbuf->buf));
	goto loaderror;
    }

    if (finfo.size != (apr_size_t)finfo.size) {
	err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			    apr_psprintf(p,
					"Opened but rejected huge file %s",
					pbuf->buf));
	goto loaderror;
    }

    amt = (apr_size_t)finfo.size;
    dav_set_bufsize(p, pbuf, amt);
    if (apr_file_read(file, pbuf->buf, &amt) != APR_SUCCESS
        || amt != finfo.size) {
	err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			    apr_psprintf(p,
					"Failure reading locknull file "
					"for %s", dirpath));

	/* just in case the caller disregards the returned error */
	pbuf->cur_len = 0;
	goto loaderror;
    }

  loaderror:
    apr_file_close(file);
    return err;
}

/*
** dav_fs_save_locknull_list:  Saves contents of pbuf into the
**    locknull file for dirpath.
*/
static dav_error * dav_fs_save_locknull_list(apr_pool_t *p, const char *dirpath,
					     dav_buffer *pbuf)
{
    const char *pathname;
    apr_file_t *file = NULL;
    dav_error *err = NULL;
    apr_size_t amt;

    if (pbuf->buf == NULL)
	return NULL;

    dav_fs_ensure_state_dir(p, dirpath);
    pathname = apr_pstrcat(p,
			  dirpath,
			  dirpath[strlen(dirpath) - 1] == '/' ? "" : "/",
			  DAV_FS_STATE_DIR "/" DAV_FS_LOCK_NULL_FILE,
			  NULL);

    if (pbuf->cur_len == 0) {
	/* delete the file if cur_len == 0 */
	if (apr_file_remove(pathname, p) != 0) {
	    return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
				 apr_psprintf(p,
					     "Error removing %s", pathname));
	}
	return NULL;
    }

    if (apr_file_open(&file, pathname,
                APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY,
                APR_OS_DEFAULT, p) != APR_SUCCESS) {
	return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			     apr_psprintf(p,
					 "Error opening %s for writing",
					 pathname));
    }

    amt = pbuf->cur_len;
    if (apr_file_write(file, pbuf->buf, &amt) != APR_SUCCESS
        || amt != pbuf->cur_len) {
	err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			    apr_psprintf(p,
					"Error writing %" APR_SIZE_T_FMT 
                                        " bytes to %s",
					pbuf->cur_len, pathname));
    }

    apr_file_close(file);
    return err;
}

/*
** dav_fs_remove_locknull_member:  Removes filename from the locknull list
**    for directory path.
*/
static dav_error * dav_fs_remove_locknull_member(apr_pool_t *p,
                                                 const char *filename,
						 dav_buffer *pbuf)
{
    dav_error *err;
    apr_size_t len;
    apr_size_t scanlen;
    char *scan;
    const char *scanend;
    char *dirpath = apr_pstrdup(p, filename);
    char *fname = strrchr(dirpath, '/');
    int dirty = 0;

    if (fname != NULL)
	*fname++ = '\0';
    else
	fname = dirpath;
    len = strlen(fname) + 1;

    if ((err = dav_fs_load_locknull_list(p, dirpath, pbuf)) != NULL) {
	/* ### add a higher level description? */
	return err;
    }

    for (scan = pbuf->buf, scanend = scan + pbuf->cur_len;
	 scan < scanend;
	 scan += scanlen) {
	scanlen = strlen(scan) + 1;
	if (len == scanlen && memcmp(fname, scan, scanlen) == 0) {
	    pbuf->cur_len -= scanlen;
	    memmove(scan, scan + scanlen, scanend - (scan + scanlen));
	    dirty = 1;
	    break;
	}
    }

    if (dirty) {
	if ((err = dav_fs_save_locknull_list(p, dirpath, pbuf)) != NULL) {
	    /* ### add a higher level description? */
	    return err;
	}
    }

    return NULL;
}

/* Note: used by dav_fs_repos.c */
dav_error * dav_fs_get_locknull_members(
    const dav_resource *resource,
    dav_buffer *pbuf)
{
    const char *dirpath;

    /* ### should test this result value... */
    (void) dav_fs_dir_file_name(resource, &dirpath, NULL);
    return dav_fs_load_locknull_list(dav_fs_pool(resource), dirpath, pbuf);
}

/* ### fold into append_lock? */
/* ### take an optional buf parameter? */
static dav_error * dav_fs_add_locknull_state(
    dav_lockdb *lockdb,
    const dav_resource *resource)
{
    dav_buffer buf = { 0 };
    apr_pool_t *p = lockdb->info->pool;
    const char *dirpath;
    const char *fname;
    dav_error *err;

    /* ### should test this result value... */
    (void) dav_fs_dir_file_name(resource, &dirpath, &fname);

    if ((err = dav_fs_load_locknull_list(p, dirpath, &buf)) != NULL) {
        return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			      "Could not load .locknull file.", err);
    }

    dav_buffer_append(p, &buf, fname);
    buf.cur_len++;	/* we want the null-term here */

    if ((err = dav_fs_save_locknull_list(p, dirpath, &buf)) != NULL) {
        return dav_push_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
			      "Could not save .locknull file.", err);
    }

    return NULL;
}

/*
** dav_fs_remove_locknull_state:  Given a request, check to see if r->filename
**    is/was a lock-null resource.  If so, return it to an existant state.
**
**    ### this function is broken... it doesn't check!
**
**    In this implementation, this involves two things:
**    (a) remove it from the list in the appropriate .DAV/locknull file
**    (b) on *nix, convert the key from a filename to an inode.
*/
static dav_error * dav_fs_remove_locknull_state(
    dav_lockdb *lockdb,
    const dav_resource *resource)
{
    dav_buffer buf = { 0 };
    dav_error *err;
    apr_pool_t *p = lockdb->info->pool;
    const char *pathname = dav_fs_pathname(resource);

    if ((err = dav_fs_remove_locknull_member(p, pathname, &buf)) != NULL) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -