/* direct_compress for fusecompress. * Copyright (C) 2005 Anders Aagaard * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. */ /* implement open/close/read/write that I put in compress_module - change functions using compress/decompress there to use a function that uses the open/close/read/write functions instead? add direct_open/direct_close/direct_read/direct_write to fusecompress'es functions. - also fi->fh has to become filedata_h, and on the top of every function using it we need to LOCK_ENTRY and UNLOCK_ENTRY on the bottom. - fuse's open/release/write/read/truncate atleast (trunc has to count as write, and decompress file if we have more accesses) - truncate is special, we can set file to RAW without running it through decompress first. */ #include #include #include #include #include #include "list.h" #include "direct_compress.h" pthread_mutex_t database_lock; database_entry_h database; static unsigned int gethash (const char *ptr) { unsigned int hash; /* todo, tweak this, no more len, base it on ptr[0]? */ for (hash = 0; *ptr; ptr++) hash = 31 * hash + *ptr; return hash; } // Returns locked database entry. database_entry_h *direct_open(char *filename, struct compress_module *compressor) { assert(filename); database_entry_h *entry = NULL; unsigned int target_hash = gethash(filename); LOCK_DATABASE; _CACHE_MSG("direct_open %s\n",filename); list_for_each_entry(entry, &database.list,list) { LOCK_ENTRY; if (entry->filename_hash == target_hash && (strcmp(entry->filename,filename) == 0)) { UNLOCK_DATABASE; entry->compressor = compressor; entry->accesses++; return entry; // RETURNED WITH LOCK } } // No entry found, allocate new. entry = malloc(sizeof(database_entry_h)); LOCK_ENTRY; entry->compressor = compressor; entry->accesses = 1; entry->filename = strdup(filename); entry->filename_hash = target_hash; list_add(&entry->list,&database.list); UNLOCK_DATABASE; } // We need LOCK_ENTRY here. void direct_close(filedata_h *filedata) { if (filedata->compressor_data) { filedata->database->compressor->close((void *)filedata->compressor_data); free(filedata->compressor_data); filedata->compressor_data = NULL; } } /* We need LOCK_ENTRY here. This function returns TRUE on data read ok (length in returned_len), FALSE on use pread instead and FAIL on error. */ int direct_decompress(filedata_h *filedata,void *buffer, size_t size, int offset, int *returned_len) { // If offset is wrong, we need to close and open in raw mode. if (offset != filedata->offset) { direct_close(filedata); if (decompress(filedata->fd,filedata->database->filename,filedata->database->compressor) == FAIL) return FAIL; filedata->database->compressor = NULL; return FALSE; } // Open file if neccesary assert(filedata->database->compressor); if (!filedata->compressor_data) { assert(filedata->offset == 0); filedata->compressor_data = COMPRESSOR_OPEN(filedata->fd,"rb"); if (!filedata->compressor_data) return FAIL; } // Do actual decompressing. assert(filedata->compressor_data); *returned_len = COMPRESSOR_READ(filedata->compressor_data,buffer,size); if (*returned_len == -1) return FAIL; return TRUE; } /* We need LOCK_ENTRY here. This function returns TRUE on data read ok (length in returned_len), FALSE on use pwrite instead and FAIL on error. */ int direct_compress(filedata_h *filedata, void *buffer, size_t size, int offset, int *returned_len) { // If accesses > 0 we need to decompress, can't have write and read (... actually we can, but lets ignore that for now) or multiple writes if (offset != filedata->offset || filedata->database->accesses > 0) { direct_close(filedata); if (decompress(filedata->fd,filedata->database->filename,filedata->database->compressor) == FAIL) return FAIL; filedata->database->compressor = NULL; return FALSE; } // Open file if neccesary assert(filedata->database->compressor); if (!filedata->compressor_data) { assert(filedata->offset == 0); filedata->compressor_data = COMPRESSOR_OPEN(filedata->fd,"wb9"); if (!filedata->compressor_data) return FAIL; } // Do actual compressing. assert(filedata->compressor_data); *returned_len = COMPRESSOR_WRITE(filedata->compressor_data,buffer,size); if (*returned_len == -1) return FAIL; return TRUE; }