int iFuseBufferedFsGetAttr(const char *iRodsPath, struct stat *stbuf) {
    int status = 0;
    std::map<std::string, iFuseBufferCache_t*>::iterator it_deltamap;
    iFuseBufferCache_t *iFuseBufferCache = NULL;
    std::string pathkey(iRodsPath);

    assert(iRodsPath != NULL);
    assert(stbuf != NULL);

    iFuseRodsClientLog(LOG_DEBUG, "iFuseBufferedFsGetAttr: %s", iRodsPath);

    status = iFuseFsGetAttr(iRodsPath, stbuf);
    if (status < 0) {
        iFuseRodsClientLogError(LOG_ERROR, status, "iFuseBufferedFsGetAttr: iFuseFsGetAttr of %s error, status = %d",
                iRodsPath, status);
        return status;
    }

    pthread_mutex_lock(&g_BufferCacheLock);

    it_deltamap = g_DeltaMap.find(pathkey);
    if(it_deltamap != g_DeltaMap.end()) {
        // has it
        iFuseBufferCache = it_deltamap->second;

        off_t newSize = iFuseBufferCache->offset + iFuseBufferCache->size;
        if(newSize > stbuf->st_size) {
            stbuf->st_size = newSize;
        }
    }

    pthread_mutex_unlock(&g_BufferCacheLock);
    return status;
}
static int _flushDelta(iFuseFd_t *iFuseFd) {
    int status = 0;
    std::map<std::string, iFuseBufferCache_t*>::iterator it_deltamap;
    iFuseBufferCache_t *iFuseBufferCache = NULL;
    std::string pathkey(iFuseFd->iRodsPath);

    assert(iFuseFd != NULL);

    if((iFuseFd->openFlag & O_ACCMODE) != O_RDONLY) {
        pthread_mutex_lock(&g_BufferCacheLock);

        it_deltamap = g_DeltaMap.find(pathkey);
        if(it_deltamap != g_DeltaMap.end()) {
            // has it - flush
            iFuseBufferCache = it_deltamap->second;

            g_DeltaMap.erase(it_deltamap);
            
            // apply to caches
            _applyDeltaToCache(iFuseFd->iRodsPath, iFuseBufferCache->buffer, iFuseBufferCache->offset, iFuseBufferCache->size);
            
            // release lock before making a write request
            pthread_mutex_unlock(&g_BufferCacheLock);
            
            status = iFuseFsWrite(iFuseFd, iFuseBufferCache->buffer, iFuseBufferCache->offset, iFuseBufferCache->size);
            if (status < 0) {
                iFuseRodsClientLogError(LOG_ERROR, status, "_flushDelta: iFuseFsWrite of %s error, status = %d",
                        iFuseFd->iRodsPath, status);
                return -ENOENT;
            }

            // release
            _freeBufferCache(iFuseBufferCache);
        } else {
            pthread_mutex_unlock(&g_BufferCacheLock);
        }
    }

    return 0;
}
static int _writeBlock(iFuseFd_t *iFuseFd, const char *buf, off_t off, size_t size) {
    int status = 0;
    std::map<std::string, iFuseBufferCache_t*>::iterator it_deltamap;
    iFuseBufferCache_t *iFuseBufferCache = NULL;
    std::string pathkey(iFuseFd->iRodsPath);

    assert(iFuseFd != NULL);
    assert(buf != NULL);
    assert(size > 0);

    pthread_mutex_lock(&g_BufferCacheLock);

    it_deltamap = g_DeltaMap.find(pathkey);
    if(it_deltamap != g_DeltaMap.end()) {
        // has it - determine flush or extend
        iFuseBufferCache = it_deltamap->second;

        if(_isSameBlock(iFuseBufferCache->offset, off) &&
            (off_t)(iFuseBufferCache->offset + iFuseBufferCache->size) >= off &&
            iFuseBufferCache->offset <= (off_t)(off + size)) {
            // intersect - expand
            off_t startOffset = off > iFuseBufferCache->offset ? iFuseBufferCache->offset : off;
            off_t endOffset = (off + size) > (iFuseBufferCache->offset + iFuseBufferCache->size) ? (off + size) : (iFuseBufferCache->offset + iFuseBufferCache->size);
            size_t newSize = endOffset - startOffset;
            char *newBuf = (char*)calloc(1, newSize);
            if(newBuf == NULL) {
                pthread_mutex_unlock(&g_BufferCacheLock);
                return SYS_MALLOC_ERR;
            }

            assert(newSize > 0);
            assert((iFuseBufferCache->offset - startOffset) >= 0);
            assert((off - startOffset) >= 0);

            memcpy(newBuf + (iFuseBufferCache->offset - startOffset), iFuseBufferCache->buffer, iFuseBufferCache->size);
            memcpy(newBuf + (off - startOffset), buf, size);

            free(iFuseBufferCache->buffer);

            iFuseBufferCache->buffer = newBuf;
            iFuseBufferCache->offset = startOffset;
            iFuseBufferCache->size = newSize;
            
            pthread_mutex_unlock(&g_BufferCacheLock);
        } else {
            char *newBuf = (char*)calloc(1, size);
            char *bufFlush = iFuseBufferCache->buffer;
            off_t offFlush = iFuseBufferCache->offset;
            size_t sizeFlush = iFuseBufferCache->size;
            
            if(newBuf == NULL) {
                pthread_mutex_unlock(&g_BufferCacheLock);
                return SYS_MALLOC_ERR;
            }
            
            // discrete
            // apply delta to caches
            _applyDeltaToCache(iFuseFd->iRodsPath, iFuseBufferCache->buffer, iFuseBufferCache->offset, iFuseBufferCache->size);
            
            memcpy(newBuf, buf, size);
            
            iFuseBufferCache->buffer = newBuf;
            iFuseBufferCache->offset = off;
            iFuseBufferCache->size = size;
            
            // release mutex before making write request
            pthread_mutex_unlock(&g_BufferCacheLock);
            
            // flush
            status = iFuseFsWrite(iFuseFd, bufFlush, offFlush, sizeFlush);
            if (status < 0) {
                iFuseRodsClientLogError(LOG_ERROR, status, "_writeBlock: iFuseFsWrite of %s error, status = %d",
                        iFuseFd->iRodsPath, status);
                return -ENOENT;
            }

            free(bufFlush);
        }
    } else {
        char *newBuf = (char*)calloc(1, size);
        if(newBuf == NULL) {
            pthread_mutex_unlock(&g_BufferCacheLock);
            return SYS_MALLOC_ERR;
        }
        
        // no delta
        status = _newBufferCache(&iFuseBufferCache);
        if(status < 0) {
            pthread_mutex_unlock(&g_BufferCacheLock);
            return status;
        }

        assert(iFuseBufferCache != NULL);

        memcpy(newBuf, buf, size);

        iFuseBufferCache->fdId = iFuseFd->fdId;
        iFuseBufferCache->iRodsPath = strdup(iFuseFd->iRodsPath);
        iFuseBufferCache->buffer = newBuf;
        iFuseBufferCache->offset = off;
        iFuseBufferCache->size = size;

        g_DeltaMap[pathkey] = iFuseBufferCache;
        
        pthread_mutex_unlock(&g_BufferCacheLock);
    }
    
    return 0;
}
static int _readBlock(iFuseFd_t *iFuseFd, char *buf, unsigned int blockID) {
    int status = 0;
    off_t blockStartOffset = 0;
    size_t readSize = 0;
    std::map<unsigned long, iFuseBufferCache_t*>::iterator it_cachemap;
    std::map<std::string, iFuseBufferCache_t*>::iterator it_deltamap;
    iFuseBufferCache_t *iFuseBufferCache = NULL;
    bool hasCache = false;
    std::string pathkey(iFuseFd->iRodsPath);

    assert(iFuseFd != NULL);
    assert(buf != NULL);
    
    blockStartOffset = getBlockStartOffset(blockID);
    
    pthread_mutex_lock(&g_BufferCacheLock);

    // check cache
    it_cachemap = g_CacheMap.find(iFuseFd->fdId);
    if(it_cachemap != g_CacheMap.end()) {
        // has it
        iFuseBufferCache = it_cachemap->second;

        if(iFuseBufferCache->offset == blockStartOffset &&
                iFuseBufferCache->buffer != NULL) {
            memcpy(buf, iFuseBufferCache->buffer, iFuseBufferCache->size);

            readSize = iFuseBufferCache->size;
            hasCache = true;
        } else {
            g_CacheMap.erase(it_cachemap);

            // release
            _freeBufferCache(iFuseBufferCache);
        }
    }
    
    // temporarily unlock mutex
    pthread_mutex_unlock(&g_BufferCacheLock);
    
    if(!hasCache) {
        char *blockBuffer = NULL;
        
        status = _newBufferCache(&iFuseBufferCache);
        if(status < 0) {
            return status;
        }

        assert(iFuseBufferCache != NULL);
        
        // read from server
        blockBuffer = (char*)calloc(1, IFUSE_BUFFER_CACHE_BLOCK_SIZE);
        if(blockBuffer == NULL) {
            _freeBufferCache(iFuseBufferCache);
            return SYS_MALLOC_ERR;
        }
        
        status = iFuseFsRead(iFuseFd, blockBuffer, blockStartOffset, IFUSE_BUFFER_CACHE_BLOCK_SIZE);
        if (status < 0) {
            iFuseRodsClientLogError(LOG_ERROR, status, "_readBlock: iFuseFsRead of %s error, status = %d",
                    iFuseFd->iRodsPath, status);
            free(blockBuffer);
            _freeBufferCache(iFuseBufferCache);
            return -ENOENT;
        }
        
        iFuseRodsClientLog(LOG_DEBUG, "_readBlock: iFuseFsRead of %s - offset: %lld, size: %lld", iFuseFd->iRodsPath, (long long)blockStartOffset, (long long)status);

        iFuseBufferCache->fdId = iFuseFd->fdId;
        iFuseBufferCache->iRodsPath = strdup(iFuseFd->iRodsPath);
        iFuseBufferCache->buffer = blockBuffer;
        iFuseBufferCache->offset = blockStartOffset;
        iFuseBufferCache->size = status;

        pthread_mutex_lock(&g_BufferCacheLock);
        
        g_CacheMap[iFuseFd->fdId] = iFuseBufferCache;

        // copy
        memcpy(buf, iFuseBufferCache->buffer, iFuseBufferCache->size);

        readSize = iFuseBufferCache->size;
        
        pthread_mutex_unlock(&g_BufferCacheLock);
    }
    
    pthread_mutex_lock(&g_BufferCacheLock);
    
    // check delta
    it_deltamap = g_DeltaMap.find(pathkey);
    if(it_deltamap != g_DeltaMap.end()) {
        // has delta
        iFuseBufferCache = it_deltamap->second;
        
        if(getBlockID(iFuseBufferCache->offset) == blockID && 
                iFuseBufferCache->buffer != NULL) {
            size_t deltaSize = 0;

            assert((iFuseBufferCache->offset - blockStartOffset) >= 0);

            memcpy(buf + (iFuseBufferCache->offset - blockStartOffset), iFuseBufferCache->buffer, iFuseBufferCache->size);

            deltaSize = (iFuseBufferCache->offset - blockStartOffset) + iFuseBufferCache->size;

            if(readSize < deltaSize) {
                readSize = deltaSize;
            }
        }
    }

    pthread_mutex_unlock(&g_BufferCacheLock);
    return readSize;
}
Exemple #5
0
char*
pathprobe_20100601(const char* lang, const char* tool, const char* aproc, int op, char* path, size_t pathsize, char* attr, size_t attrsize)
{
	char*		proc = (char*)aproc;
	register char*	p;
	register char*	k;
	register char*	x;
	register char**	ap;
	int		n;
	int		v;
	int		force;
	ssize_t		r;
	char*		e;
	char*		np;
	char*		nx;
	char*		probe;
	const char*	dirs;
	const char*	dir;
	Proc_t*		pp;
	Sfio_t*		sp;
	char		buf[PATH_MAX];
	char		cmd[PATH_MAX];
	char		exe[PATH_MAX];
	char		lib[PATH_MAX];
	char		ver[PATH_MAX];
	char		key[16];
	char*		arg[8];
	long		ops[2];
	unsigned long	ptime;
	struct stat	st;
	struct stat	ps;

	if (*proc != '/')
	{
		if (p = strchr(proc, ' '))
		{
			strncopy(buf, proc, p - proc + 1);
			proc = buf;
		}
		if (!(proc = pathpath(proc, NiL, PATH_ABSOLUTE|PATH_REGULAR|PATH_EXECUTE, cmd, sizeof(cmd))))
			proc = (char*)aproc;
		else if (p)
		{
			n = strlen(proc);
			strncopy(proc + n, p, PATH_MAX - n - 1);
		}
	}
	if (!path)
	{
		path = buf;
		pathsize = sizeof(buf);
	}
	probe = PROBE;
	x = lib + sizeof(lib) - 1;
	k = lib + sfsprintf(lib, x - lib, "lib/%s/", probe);
	p = k + sfsprintf(k, x - k, "%s/%s/", lang, tool);
	pathkey(lang, tool, proc, key, sizeof(key), attr, attrsize);
	if (op >= -2)
	{
		strncopy(p, key, x - p);
		if (pathpath(lib, "", PATH_ABSOLUTE, path, pathsize) && !stat(path, &st) && (st.st_mode & S_IWUSR))
			return path == buf ? strdup(path) : path;
	}
	e = strncopy(p, probe, x - p);
	if (!pathpath(lib, "", PATH_ABSOLUTE|PATH_EXECUTE, path, pathsize) || stat(path, &ps))
		return 0;
	for (;;)
	{
		ptime = ps.st_mtime;
		n = strlen(path);
		if (n < (PATH_MAX - 5))
		{
			strcpy(path + n, ".ini");
			if (!stat(path, &st) && st.st_size && ptime < (unsigned long)st.st_mtime)
				ptime = st.st_mtime;
			path[n] = 0;
		}
		np = path + n - (e - k);
		nx = path + PATH_MAX - 1;
		strncopy(np, probe, nx - np);
		if (!stat(path, &st))
			break;

		/*
		 * yes lib/probe/<lang>/<proc>/probe
		 *  no lib/probe/probe
		 *
		 * do a manual pathaccess() to find a dir with both
		 */

		sfsprintf(exe, sizeof(exe), "lib/%s/%s", probe, probe);
		dirs = pathbin();
		for (;;)
		{
			if (!(dir = dirs))
				return 0;
			dirs = pathcat(dir, ':', "..", exe, path, pathsize);
			pathcanon(path, pathsize, 0);
			if (*path == '/' && pathexists(path, PATH_REGULAR|PATH_EXECUTE))
			{
				pathcat(dir, ':', "..", lib, path, pathsize);
				pathcanon(path, pathsize, 0);
				if (*path == '/' && pathexists(path, PATH_REGULAR|PATH_EXECUTE) && !stat(path, &ps))
					break;
			}
		}
	}
	strncopy(p, key, x - p);
	p = np;
	x = nx;
	strcpy(exe, path);
	if (op >= -1 && (!(st.st_mode & S_ISUID) && ps.st_uid != geteuid() || rofs(path)))
	{
		if (!(p = getenv("HOME")))
			return 0;
		p = path + sfsprintf(path, PATH_MAX - 1, "%s/.%s/%s/", p, probe, HOSTTYPE);
	}
	strncopy(p, k, x - p);
	force = 0;
	if (op >= 0 && !stat(path, &st))
	{
		if (ptime <= (unsigned long)st.st_mtime || ptime <= (unsigned long)st.st_ctime)
		{
			/*
			 * verify (<sep><name><sep><option><sep><value>)* header
			 */

			if (sp = sfopen(NiL, path, "r"))
			{
				if (x = sfgetr(sp, '\n', 1))
				{
					while (*x && *x != ' ')
						x++;
					while (*x == ' ')
						x++;
					if (n = *x++)
						for (;;)
						{
							for (k = x; *x && *x != n; x++);
							if (!*x)
								break;
							*x++ = 0;
							for (p = x; *x && *x != n; x++);
							if (!*x)
								break;
							*x++ = 0;
							for (e = x; *x && *x != n; x++);
							if (!*x)
								break;
							*x++ = 0;
							if (streq(k, "VERSION"))
							{
								ap = arg;
								*ap++ = proc;
								*ap++ = p;
								*ap = 0;
								ops[0] =  PROC_FD_DUP(1, 2, 0);
								ops[1] = 0;
								if (pp = procopen(proc, arg, NiL, ops, PROC_READ))
								{
									if ((v = x - e) >= sizeof(ver))
										v = sizeof(ver) - 1;
									for (k = p = ver;; k++)
									{
										if (k >= p)
										{
											if (v <= 0 || (r = read(pp->rfd, k, v)) <= 0)
												break;
											v -= r;
											p = k + r;
										}
										if (*k == '\n' || *k == '\r')
											break;
										if (*k == n)
											*k = ' ';
									}
									*k = 0;
									if (strcmp(ver, e))
									{
										force = 1;
										error(0, "probe processor %s version \"%s\" changed -- expected \"%s\"", proc, ver, e);
									}
									procclose(pp);
								}
								break;
							}
						}
				}
				sfclose(sp);
			}
			if (!force)
				op = -1;
		}
		if (op >= 0 && (st.st_mode & S_IWUSR))
		{
			if (op == 0)
				error(0, "%s probe information for %s language processor %s must be manually regenerated", tool, lang, proc);
			op = -1;
			force = 0;
		}
	}
	if (op >= 0)
	{
		ap = arg;
		*ap++ = exe;
		if (force)
			*ap++ = "-f";
		if (op > 0)
			*ap++ = "-s";
		*ap++ = (char*)lang;
		*ap++ = (char*)tool;
		*ap++ = proc;
		*ap = 0;
		if (procrun(exe, arg, 0))
			return 0;
		if (eaccess(path, R_OK))
			return 0;
	}
	return path == buf ? strdup(path) : path;
}