/* filelist.c -- Copyright 1989, 1993, 1994, 1996 Liam R. E. Quin. * All Rights Reserved. * This code is NOT in the public domain. * See the file COPYRIGHT for full details. */ /* * * filelist -- operations on the list of files. This is the Document * Directory part of lq-Text. * * $Id: fileinfo.c,v 1.37 96/07/04 20:04:43 lee Exp $ * */ #include "globals.h" /* defines and declarations for database filenames */ #include "error.h" #include #include #include #include #include #ifdef HAVE_FCNTL_H # include #endif #ifdef HAVE_STRING_H # include #else # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_STDLIB_H # include #else # include #endif #include "lqutil.h" #include "liblqtext.h" #include "smalldb.h" #include "fileinfo.h" #include "emalloc.h" #include "numbers.h" #include "filter.h" /* used by LQT_DestroyFileInfo */ /** Unix system calls that need to be declared: **/ /** library functions that need to be declared: */ /** **/ typedef struct { unsigned int Size; unsigned char *Buffer; } t_PhysicalIndexEntry; #define EXTRABYTES (sizeof(long)*5 + 1) /* enough for all the "members" */ PRIVATE t_PhysicalIndexEntry * FileInfo2Phys(FileInfo) t_FileInfo *FileInfo; { t_PhysicalIndexEntry *PIE; unsigned char *p; register int NameLength; if (!FileInfo || !FileInfo->Name) return (t_PhysicalIndexEntry *) 0; NameLength = strlen(FileInfo->Name); PIE = (t_PhysicalIndexEntry *) emalloc("Physical Index Entry", sizeof(t_PhysicalIndexEntry) + NameLength + 1); p = PIE->Buffer = (unsigned char *) emalloc("File Name", NameLength + EXTRABYTES + 1); /* warning: update EXTRABYTES when editing this code... See above. */ (void) LQT_sWriteNumber(&p, FileInfo->FID, PIE->Buffer, EXTRABYTES); (void) LQT_sWriteNumber(&p, FileInfo->Date, PIE->Buffer, EXTRABYTES); (void) LQT_sWriteNumber(&p, FileInfo->FilterType, PIE->Buffer, EXTRABYTES); (void) LQT_sWriteNumber(&p, (long) NameLength, PIE->Buffer, EXTRABYTES); (void) LQT_sWriteNumber(&p, FileInfo->FileSize, PIE->Buffer, EXTRABYTES); *p++ = FileInfo->Flags; (void) strcpy(p, FileInfo->Name); PIE->Size = (long) (&p[NameLength] - PIE->Buffer); return (t_PhysicalIndexEntry *) erealloc((char *)PIE, PIE->Size); } PRIVATE t_FileInfo * Phys2FileInfo(PIE) t_PhysicalIndexEntry *PIE; { t_FileInfo *FileInfo; unsigned char *p; unsigned long NameLength; if (!PIE || !PIE->Buffer) return (t_FileInfo *) 0; FileInfo = (t_FileInfo *) emalloc("FileInfo for PIE", sizeof(t_FileInfo)); p = PIE->Buffer; /* The order of these must match the order of the LQT_sWriteNumber calls in * FileInfo2Phys() above! */ (void) LQT_sReadNumber(&p, &FileInfo->FID, p, EXTRABYTES); (void) LQT_sReadNumber(&p, &FileInfo->Date, p, EXTRABYTES); (void) LQT_sReadNumber(&p, &FileInfo->FilterType, p, EXTRABYTES); (void) LQT_sReadNumber(&p, &NameLength, p, EXTRABYTES); (void) LQT_sReadNumber(&p, &FileInfo->FileSize, p, EXTRABYTES); FileInfo->Flags = *p++; FileInfo->Stream = (FILE *) 0; if (NameLength) { FileInfo->Name = emalloc("File Name", NameLength + 1); (void) strncpy(FileInfo->Name, p, NameLength); FileInfo->Name[NameLength] = '\0'; /* Note: we trust the name to be plausible. * If the file has been removed or renamed, we might still * want to know the old name, se there is no point checking. * In any case, on some systems stat() is very slow, so that * checking to see if the file is there should only be done if * necessary. */ } else { FileInfo->Name = (char *) 0; } return FileInfo; } /* * LQT_SaveFileInfo * Database/Update, Database/Documents * * Stores the given t_FileInfo structure in the database referred * to by the given db argument, whence it * can be retrieved by FID or by filename. * * *
  • zero on success *
  • -1 if error * * * Warns if the database can't be opened or written to. * * LQT_RemoveFileInfoFromIndex, LQT_DestroyFileInfo * */ API int LQT_SaveFileInfo(db, FileInfo) t_LQTEXT_Database *db; t_FileInfo *FileInfo; { t_PhysicalIndexEntry *PIE; datum key, data; int RetVal; unsigned char Buffer[20]; unsigned char *p; DBM *fileDB; if (!FileInfo) return -1; if ((PIE = FileInfo2Phys(FileInfo)) == (t_PhysicalIndexEntry *) 0) { return -1; } if ((fileDB = LQT_OpenKeyValueDatabase(db, db->FileIndex)) == (DBM *) 0) { (void) efree((char *) PIE); return -1; } p = Buffer; (void) LQT_sWriteNumber(&p, FileInfo->FID, p, sizeof Buffer); data.dptr = (char *) Buffer; data.dsize = p - Buffer; if (FileInfo->Name && *(FileInfo->Name)) { int KeyLen = strlen(FileInfo->Name); unsigned char *tmp; key.dptr = emalloc("dbm key for file name", KeyLen + 2); /* +2: "\375" and \0 */ tmp = key.dptr; *tmp = '\375'; (void) strcpy(&tmp[1], FileInfo->Name); key.dsize = KeyLen + 1; /* length of name + length of "\375" -- the nul at the end * is not included. */ (void) dbm_store(fileDB, key, data, DBM_REPLACE); (void) efree(key.dptr); } key.dptr = data.dptr; key.dsize = data.dsize; data.dptr = (char *) PIE->Buffer; data.dsize = PIE->Size; RetVal = dbm_store(fileDB, key, data, DBM_REPLACE); (void) efree((char *) PIE->Buffer); (void) efree((char *) PIE); LQT_CloseKeyValueDatabase(fileDB); return RetVal; } /* * LQT_RenameFileInIndex * Database/Update, Database/Documents * * Changes the filename associated with a FID, by finding the FID * for the old filename and then replacing its filename. * * *
  • zero on success *
  • -1 on error * * * Warns if the database can't be opened or the file isn't indexed. * */ API int LQT_RenameFileInIndex(db, OldName, NewName) t_LQTEXT_Database *db; char *OldName; char *NewName; { t_FID FID; t_FileInfo *FileInfo; datum key, result; int n; DBM *fileDB; FID = LQT_NameToFID(db, NewName); if (FID) { Error(E_WARN, "lqReNameFile: rename %s to %s failed, new name has entry (%ld)", OldName, NewName, FID ); return -1; } FID = LQT_NameToFID(db, OldName); FileInfo = LQT_FIDToFileInfo(db, FID); n = strlen(NewName); key.dsize = strlen(OldName); /* see previous routine for comments about this +2 ugliness */ if (n > key.dsize) { key.dptr = emalloc("File Name for dbm rename", n + 2); } else { key.dptr = emalloc("Smaller File Name for dbm resize", key.dsize + 2); } { unsigned char *tmp = key.dptr; *tmp = (unsigned char) '\375'; (void) strcpy(&tmp[1], OldName); key.dsize += 1; /* for the cookie; we don't include the \0 */ } if ((fileDB = LQT_OpenKeyValueDatabase(db, db->FileIndex)) == (DBM *) 0) { Error(E_WARN|E_SYS, "LQT_RenameFileInIndex can't open database \"%s\" to rename %s", db->FileIndex, OldName ); (void) efree(key.dptr); return -1; } result = dbm_fetch(fileDB, key); /* If it was there, delete it */ if (result.dptr != (char *) 0 && result.dsize != 0) { (void) dbm_delete(fileDB, key); } else { Error(E_WARN|E_SYS, "LQT_RenameFileInIndex can't get FID for %s from database \"%s\"", OldName, db->FileIndex ); (void) efree(key.dptr); LQT_CloseKeyValueDatabase(fileDB); return -1; } /* Now make a new one */ { unsigned char *tmp = key.dptr; *tmp = (unsigned char) '\375'; (void) strcpy(&tmp[1], NewName); key.dsize = n + 1; /* for the cookie; we don't include the \0 */ (void) dbm_store(fileDB, key, result, DBM_REPLACE); /* Now change the reverse map */ (void) strcpy(tmp, NewName); key.dsize = n; /* TODO: FIXME: what should be here? NOTDONE! */ } (void) efree(key.dptr); FileInfo->Name = NewName; LQT_CloseKeyValueDatabase(fileDB); return LQT_SaveFileInfo(db, FileInfo); } /* * LQT_NameToFID * Database/Retrieval, Database/Documents * * Returns the FID associated with a given file name * * *
  • the FID on success *
  • zero on failure * * * LQT_FIDToFileInfo * LQT_GetMaxOrAllocateFID * * Warns if the database can't be opened. * If the filename is not matched in the database, no warning * is given, but zero is returned. * */ API t_FID LQT_NameToFID(db, Name) t_LQTEXT_Database *db; char *Name; { datum key, result; DBM *fileDB; if ((fileDB = LQT_OpenKeyValueDatabase(db, db->FileIndex)) == (DBM *) 0) { Error(E_WARN|E_SYS, "LQT_NameToFID can't get FID for %s (database \"%s\")", Name, db->FileIndex ); return (t_FID) 0; } key.dsize = strlen(Name); /* see previous routine for comments about this +2 ugliness */ key.dptr = emalloc("File Name for LQT_NameToFID dbm key", key.dsize + 2); { unsigned char *tmp = key.dptr; *tmp = (unsigned char) '\375'; (void) strcpy(&tmp[1], Name); key.dsize += 1; /* for the cookie; we don't include the \0 */ } result = dbm_fetch(fileDB, key); LQT_CloseKeyValueDatabase(fileDB); (void) efree(key.dptr); if (result.dptr == (char *) 0 || result.dsize == 0) { return (t_FID) 0; } else { t_FID FID; (void) LQT_sReadNumber( (unsigned char **) &result.dptr, &FID, (unsigned char *) result.dptr, 100 ); return FID; } } /* * LQT_FIDToFileInfo * Database/Retrieval, Database/Documents * * Returns the in-memory t_FileInfo struct associated with a given FID, * reading the information from the database as necessary. * The returned value, if non-zero, is created with malloc; it is * the caller's responsibility to free the storage. * * LQT_NameToFID, LQT_DestroyFileInfo * * *
  • the t_FileInfo * on success; *
  • NULL on error. * * * Warns if the database can't be opened. * * LQT_NameToFID * LQT_DestroyFileInfo * */ API t_FileInfo * LQT_FIDToFileInfo(db, FID) t_LQTEXT_Database *db; t_FID FID; { t_FileInfo *FileInfo; datum key, data; unsigned char Buffer[20]; unsigned char *p = Buffer; DBM *fileDB; LQT_sWriteNumber(&p, FID, Buffer, sizeof Buffer); key.dptr = (char *) Buffer; key.dsize = p - Buffer; if ((fileDB = LQT_OpenKeyValueDatabase(db, db->FileIndex)) == (DBM *) 0) { return (t_FileInfo *) 0; } data = dbm_fetch(fileDB, key); if (data.dptr == (char *) 0 || data.dsize == 0) { LQT_CloseKeyValueDatabase(db); return (t_FileInfo *) 0; } { t_PhysicalIndexEntry PIEb; PIEb.Size = data.dsize + 1; /* +1 because we don't store the \0 */ PIEb.Buffer = (unsigned char *) data.dptr; FileInfo = Phys2FileInfo(&PIEb); } LQT_CloseKeyValueDatabase(db); return FileInfo; } /* * LQT_DestroyFileInfo * Database/Documents, Memory * * Frees the memory used by the given FileInfo. * Neither the database nor the file described by the FileInfo is * affected; LQT_DestroyFileInfo frees any internal data structures * associated with the FileInfo and then frees the FileInfo itself. * After calling LQT_DestroyFileInfo, the FileInfo pointer is no longer * valid, and should not be dereferenced. * * LQT_NameToFID * LQT_FIDToFileInfo * */ API void LQT_DestroyFileInfo(db, FileInfo) t_LQTEXT_Database *db; t_FileInfo *FileInfo; { if (FileInfo->Stream) { if (FileInfo->FilterType >= 0 && FileInfo->FilterType <= LQT_MaxFilterType(db) && LQTpFilterTable[FileInfo->FilterType].closeFile ) { (void) (* LQTpFilterTable[FileInfo->FilterType].closeFile)( FileInfo->Stream ); } FileInfo->Stream = (FILE *) 0; } if (FileInfo->Name) { (void) efree(FileInfo->Name); } (void) efree((char *) FileInfo); } /* * LQT_RemoveFileInfoFromIndex * Database/Update, Database/Documents * * Removes the given FileInfo from the FID<-->FileInfo maps. * It is the caller's responsibility to ensure that the given FID * is not referenced anywhere in a saved WordPlace. * * *
  • zero on success *
  • -1 on error * * * LQT_NameToFID * LQT_DestroyFileInfo * * Warns if the database can't be opened * */ API int LQT_RemoveFileInfoFromIndex(db, FileInfo) t_LQTEXT_Database *db; t_FileInfo *FileInfo; { datum key, data; int RetVal; unsigned char Buffer[20]; unsigned char *p; DBM *fileDB; if (!FileInfo) return -1; if ((fileDB = LQT_OpenKeyValueDatabase(db, db->FileIndex)) == (DBM *) 0) { return -1; } p = Buffer; (void) LQT_sWriteNumber(&p, FileInfo->FID, p, sizeof Buffer); data.dptr = (char *) Buffer; data.dsize = p - Buffer; if (FileInfo->Name && *(FileInfo->Name)) { int KeyLen = strlen(FileInfo->Name); unsigned char *tmp; key.dptr = emalloc("dbm key for file name", KeyLen + 2); /* +2: "\375" and \0 */ tmp = key.dptr; *tmp = (unsigned char) '\375'; (void) strcpy(&tmp[1], FileInfo->Name); key.dsize = KeyLen + 1; /* length of name + length of "\375" -- the nul at the end * is not included. */ (void) dbm_delete(fileDB, key); (void) efree(key.dptr); } key.dptr = data.dptr; key.dsize = data.dsize; RetVal = dbm_delete(fileDB, key); LQT_CloseKeyValueDatabase(fileDB); /* TODO: remove the block<-->byte mapping, if there is one */ return RetVal; }