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; }
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; }