/* ** Return the directory of a file path name. The directory is all components ** except the last one. For example, the directory of "/a/b/c.d" is "/a/b". ** If there is no directory, NULL is returned; otherwise, the returned memory ** should be freed via fossil_free(). */ char *file_dirname(const char *z){ const char *zTail = file_tail(z); if( zTail && zTail!=z ){ return mprintf("%.*s", (int)(zTail-z-1), z); }else{ return 0; } }
/* * set directory for temporary files. path will be stored in * tmpdir[] with an appropriate trailing path separator. */ void settmpdir(char *path) { char *p; if (path == NULL || *path == '\0') { tmpdir[0] = '\0'; return; } strcpy(tmpdir, path); p = tmpdir + strlen(tmpdir) - 1; #ifdef MACTC5 if (*p != '/' && *p != '\\' && *p != ']' && *p != ':') { /* append path separator, either / or \ */ if ((p = strchr(tmpdir, '/')) == NULL && (p = strchr(tmpdir, '\\')) == NULL && (p = strchr(tmpdir, ':')) == NULL) p = ":"; /* path did not contain / or \ or :, use : */ strncat(tmpdir, p, 1); #else if (*p != '/' && *p != '\\' && *p != ']' && *p != ':') { /* append path separator, either / or \ */ if ((p = strchr(tmpdir, '/')) == NULL && (p = strchr(tmpdir, '\\')) == NULL) p = "/"; /* path did not contain / or \, use / */ strncat(tmpdir, p, 1); #endif } } /* * set output directory to avoid a file copy when temp file is renamed to * output file. the argument filename must be a valid path for a file, not * a directory. */ void setoutdir(char *filename) { char *p; if (filename == NULL) { strcpy(outdir, tmpdir); return; } strcpy(outdir, filename); p = file_tail(outdir); strcpy(tmpbasename, p); *p = '\0'; drop_extension(tmpbasename); #if !defined(BSD42) && !defined(BSD43) && !defined(sun) /* * we don't depend on pathconf here, if it returns an incorrect value * for NAME_MAX (like Linux 0.97 with minix FS) finding a unique name * for temp files can fail. */ tmpbasename[10] = '\0'; /* 14 char limit */ #endif }
/* truncate the filename so that an extension can be tacked on. */ static void truncate_name(char *path, int ext_len) { #ifdef UNIX /* for other systems this is a no-op */ char *p; #ifdef MAX_NAMELEN /* overrides the use of pathconf() */ int namemax = MAX_NAMELEN; #else int namemax; #ifdef _PC_NAME_MAX char dir[MAX_PATH]; strcpy(dir, path); if ((p = strrchr(dir, '/')) == NULL) { strcpy(dir, "."); } else { if (p == dir) ++p; *p = '\0'; } if ((namemax = pathconf(dir, _PC_NAME_MAX)) <= ext_len) return; #else #ifdef NAME_MAX namemax = NAME_MAX; #else namemax = 14; #endif /* NAME_MAX */ #endif /* _PC_NAME_MAX */ #endif /* MAX_NAMELEN */ if ((p = strrchr(path, '/')) == NULL) p = path; else ++p; if (strlen(p) > namemax - ext_len) { if (verbose) fprintf(pgpout, "Truncating filename '%s' ", path); p[namemax - ext_len] = '\0'; if (verbose) fprintf(pgpout, "to '%s'\n", path); } #else #ifdef MACTC5 char *p; p = file_tail(path); if (verbose) fprintf(pgpout, LANG("Truncating filename '%s' "), path); if (strlen(p) + ext_len > MAX_NAMELEN) p[MAX_NAMELEN - ext_len] = '\0'; #endif /* MACTC5 */ #endif /* UNIX */ }
/** * FUNCTION: jvmCallocImpl() * TYPE: public operation * OVERVIEW: Allocate memory from the private JVM memory pool, * memory contents are cleared * INTERFACE: * parameters: nelem Number of elements to allocate * elsize Size of one element * filename Filename where allocation occured * lineno Line number where allocation occured * returns: pointer to the newly allocated and cleared memory * */ void* jvmCallocImpl(unsigned int nelem, unsigned int elsize, char* filename, int lineno) { void *loc = NULL; if (jvm_trace_malloc) { tty->print_cr("Calloc %s:%d: ", file_tail(filename), lineno); } if ((loc = jvmMallocImpl((nelem) * (elsize), filename, lineno)) != NULL) { JVM_Memset(loc, 0, nelem * elsize); } return loc; }
/* * Returns TRUE if user left off file extension, allowing default. * Note that the name is misleading if multiple dots are allowed. * not_pgp_extension or something would be better. */ boolean no_extension(char *filename) { #ifdef MULTIPLE_DOTS /* filename can have more than one dot */ if (has_extension(filename, ASC_EXTENSION) || has_extension(filename, PGP_EXTENSION) || has_extension(filename, SIG_EXTENSION) || #ifdef MACTC5 has_extension(filename,".tmp") || #endif is_tempfile(filename)) return FALSE; else return TRUE; #else filename = file_tail(filename); return strrchr(filename, '.') == NULL; #endif } /* no_extension */
/* ** COMMAND: mv ** COMMAND: rename* ** ** Usage: %fossil mv|rename OLDNAME NEWNAME ** or: %fossil mv|rename OLDNAME... DIR ** ** Move or rename one or more files or directories within the repository tree. ** You can either rename a file or directory or move it to another subdirectory. ** ** This command does NOT rename or move the files on disk. This command merely ** records the fact that filenames have changed so that appropriate notations ** can be made at the next commit/checkin. ** ** See also: changes, status */ void mv_cmd(void){ int i; int vid; char *zDest; Blob dest; Stmt q; db_must_be_within_tree(); vid = db_lget_int("checkout", 0); if( vid==0 ){ fossil_panic("no checkout rename files in"); } if( g.argc<4 ){ usage("OLDNAME NEWNAME"); } zDest = g.argv[g.argc-1]; db_begin_transaction(); file_tree_name(zDest, &dest, 1); db_multi_exec( "UPDATE vfile SET origname=pathname WHERE origname IS NULL;" ); db_multi_exec( "CREATE TEMP TABLE mv(f TEXT UNIQUE ON CONFLICT IGNORE, t TEXT);" ); if( file_wd_isdir(zDest)!=1 ){ Blob orig; if( g.argc!=4 ){ usage("OLDNAME NEWNAME"); } file_tree_name(g.argv[2], &orig, 1); db_multi_exec( "INSERT INTO mv VALUES(%B,%B)", &orig, &dest ); }else{ if( blob_eq(&dest, ".") ){ blob_reset(&dest); }else{ blob_append(&dest, "/", 1); } for(i=2; i<g.argc-1; i++){ Blob orig; char *zOrig; int nOrig; file_tree_name(g.argv[i], &orig, 1); zOrig = blob_str(&orig); nOrig = blob_size(&orig); db_prepare(&q, "SELECT pathname FROM vfile" " WHERE vid=%d" " AND (pathname='%q' OR (pathname>'%q/' AND pathname<'%q0'))" " ORDER BY 1", vid, zOrig, zOrig, zOrig ); while( db_step(&q)==SQLITE_ROW ){ const char *zPath = db_column_text(&q, 0); int nPath = db_column_bytes(&q, 0); const char *zTail; if( nPath==nOrig ){ zTail = file_tail(zPath); }else{ zTail = &zPath[nOrig+1]; } db_multi_exec( "INSERT INTO mv VALUES('%q','%q%q')", zPath, blob_str(&dest), zTail ); } db_finalize(&q); } } db_prepare(&q, "SELECT f, t FROM mv ORDER BY f"); while( db_step(&q)==SQLITE_ROW ){ const char *zFrom = db_column_text(&q, 0); const char *zTo = db_column_text(&q, 1); mv_one_file(vid, zFrom, zTo); } db_finalize(&q); db_end_transaction(0); }
/** * FUNCTION: jvmFreeImpl() * TYPE: public operation * OVERVIEW: Free memory allocated from the private JVM memory pool * INTERFACE: * parameters: ptr Pointer to allocated memory * filename Filename where allocation occured * lineno Line number where allocation occured * returns: <nothing> * */ void jvmFreeImpl(void *ptr, char *filename, int lineno) { _JvmMemHdrPtr jvmMemoryHdr; int guardSize = 0; if(jvm_tag_malloc) { guardSize = 4; } if (ptr == NULL) { #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_INFORMATION reportToLog(LOG_INFORMATION, LC_MALLOC, "DEBUG: Attempt to free NULL pointer"); printAllocation(LOG_INFORMATION, "freed", filename, lineno); #endif #endif } else if (((char*)ptr > JvmMemoryEnd) || ((char*)ptr < JvmMemoryStart)) { #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_ERROR reportToLog(LOG_ERROR, LC_MALLOC, "ERROR: Attempt to free memory out of scope: 0x%p", ptr); printAllocation(LOG_ERROR, "freed", filename, lineno); #endif #endif } else { jvmMemoryHdr = (_JvmMemHdrPtr)((char*)ptr -sizeof(_JvmMemHdr)); if (jvm_trace_malloc) { tty->print("|%x| Free, total=%d, %s:%d ", ptr, jvm_malloc_total, file_tail(filename), lineno); } if (jvmMemoryHdr->magic != MAGIC) { if(jvm_tag_malloc) { tty->print_cr(" **** BAD TAG (0x%x) **** \n", jvmMemoryHdr->magic); } #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_ERROR reportToLog(LOG_ERROR, LC_MALLOC, "ERROR: Attempt to free corrupted memory: 0x%p", ptr); printAllocation(LOG_ERROR, "freed", filename, lineno); #endif #endif } else if (jvmMemoryHdr->free != 0) { #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_ERROR reportToLog(LOG_ERROR, LC_MALLOC, "ERROR: Attempt to free memory twice: 0x%p", ptr); printAllocation(LOG_ERROR, "freed", filename, lineno); #endif #endif } else { if(jvm_tag_malloc) { if (*(((char*)ptr) + jvmMemoryHdr->size - guardSize + 0) != (char)0x01 || *(((char*)ptr) + jvmMemoryHdr->size - guardSize + 1) != (char)0xcd || *(((char*)ptr) + jvmMemoryHdr->size - guardSize + 2) != (char)0x02 || *(((char*)ptr) + jvmMemoryHdr->size - guardSize + 3) != (char)0xef) { tty->print_cr(" **** BAD POST TAG **** "); } } else { #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_WARNING JvmMemoryAllocated -= jvmMemoryHdr->size; /* The memory block header is valid, now check the guard data */ if (jvmMemoryHdr->guard != GUARD_WORD) { reportToLog(LOG_WARNING, LC_MALLOC, "ERROR: Possible memory underrun: 0x%p", ptr); printAllocation(LOG_WARNING, "allocated", jvmMemoryHdr->filename, jvmMemoryHdr->lineno); printAllocation(LOG_WARNING, "freed", filename, lineno); } else if (verifyTailGuardData(jvmMemoryHdr)) { reportToLog(LOG_WARNING, LC_MALLOC, "ERROR: Possible memory overrun: 0x%p", ptr); printAllocation(LOG_WARNING, "allocated", jvmMemoryHdr->filename, jvmMemoryHdr->lineno); printAllocation(LOG_WARNING, "freed", filename, lineno); } #endif #endif } #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_INFORMATION reportToLog(LOG_INFORMATION, LC_MALLOC, "DEBUG: free %d bytes: 0x%p", jvmMemoryHdr->size, ptr); printAllocation(LOG_INFORMATION, "allocated", jvmMemoryHdr->filename, jvmMemoryHdr->lineno); printAllocation(LOG_INFORMATION, "freed", filename, lineno); #else (void)filename; /* No-op */ (void)lineno; /* No-op */ #endif #endif jvmMemoryHdr->free = 1; if(jvm_tag_malloc) { jvm_malloc_total -= (jvmMemoryHdr->size - guardSize); } if (jvm_trace_malloc) { tty->print_cr("OK"); } } if (jvm_trash_malloc) { if (jvmMemoryHdr->size < 1024) { JVM_Memset(ptr, 0xaf, jvmMemoryHdr->size); } } } /* end of else */ }
/** * FUNCTION: jvmMallocImpl() * TYPE: public operation * OVERVIEW: Allocate memory from the private JVM memory pool * INTERFACE: * parameters: size Number of byte to allocate * filename Filename where allocation occured * lineno Line number where allocation occured * returns: pointer to the newly allocated memory * */ void* jvmMallocImpl(unsigned int size, char* filename, int lineno) { unsigned int numBytesToAllocate = size; void* loc = NULL; _JvmMemHdrPtr tempHdr = NULL; char* temp = NULL; char* jvmMemoryPtr; char* jvmMemoryLast; _JvmMemHdrPtr jvmMemoryHdr; int guardSize = 0; void* guardPos; if (jvm_tag_malloc) { guardSize = 4; } else { #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_WARNING guardSize = GUARD_SIZE; #endif #endif } while ( (numBytesToAllocate & ALIGNMENT) != 0 ) { numBytesToAllocate++; size++; } numBytesToAllocate += guardSize; jvmMemoryLast = JvmMemoryStart; /* find a free slot */ for (jvmMemoryPtr = JvmMemoryStart; jvmMemoryPtr < JvmMemoryEnd; jvmMemoryLast = jvmMemoryPtr, jvmMemoryPtr += jvmMemoryHdr->size + sizeof(_JvmMemHdr)) { jvmMemoryHdr = (_JvmMemHdrPtr)jvmMemoryPtr; if (jvmMemoryHdr->magic != MAGIC) { tty->print_cr("ERROR: Memory corruption at 0x%p, in chunk 0x%p", jvmMemoryPtr, jvmMemoryLast); return((void *) 0); } else { while ( 1 ) { /* coalescing */ if (jvmMemoryHdr->free == 1) { /* if current block is free */ temp = (char*)jvmMemoryHdr; temp += jvmMemoryHdr->size + sizeof(_JvmMemHdr); tempHdr = (_JvmMemHdrPtr)temp; if ((temp < JvmMemoryEnd) && (tempHdr->free == 1) && (tempHdr->magic == MAGIC)) { /* and the next block is free too */ /* then coalesce */ jvmMemoryHdr->size += tempHdr->size + sizeof(_JvmMemHdr); #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_INFORMATION reportToLog(LOG_INFORMATION, LC_MALLOC, "DEBUG: Coalescing blocks 0x%p and 0x%p", jvmMemoryHdr, tempHdr); #endif #endif } else { break; } } else { break; } } /* while */ /* allocating */ if ((jvmMemoryHdr->free == 1) && (jvmMemoryHdr->size >= numBytesToAllocate)) { if (jvmMemoryHdr->size > (numBytesToAllocate + sizeof(_JvmMemHdr) + 4)) { /* split block */ _JvmMemHdrPtr nextHdr; nextHdr = (_JvmMemHdrPtr)((char *)jvmMemoryPtr + numBytesToAllocate + sizeof(_JvmMemHdr)); nextHdr->magic = MAGIC; nextHdr->free = 1; nextHdr->size = jvmMemoryHdr->size - numBytesToAllocate - sizeof(_JvmMemHdr); jvmMemoryHdr->size = numBytesToAllocate; } else { size = jvmMemoryHdr->size - guardSize; } jvmMemoryHdr->free = 0; loc = (void*)((char*)jvmMemoryHdr + sizeof(_JvmMemHdr)); if (jvm_tag_malloc) { /* Add tail guard */ guardPos = (void*)((char*)loc + jvmMemoryHdr->size - guardSize); ((unsigned char*)guardPos)[0] = (char)0x01; ((unsigned char*)guardPos)[1] = (char)0xcd; ((unsigned char*)guardPos)[2] = (char)0x02; ((unsigned char*)guardPos)[3] = (char)0xef; } else { #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_WARNING jvmMemoryHdr->guard = GUARD_WORD; /* Add head guard */ jvmMemoryHdr->filename = filename; jvmMemoryHdr->lineno = lineno; /* Add tail guard */ guardSize = jvmMemoryHdr->size - size; jvmMemoryHdr->guardSize = guardSize; guardPos = (void*)((char*)loc + jvmMemoryHdr->size - guardSize); for(i=0; i<guardSize; i++) { ((unsigned char*)guardPos)[i] = GUARD_BYTE; } JvmMemoryAllocated += numBytesToAllocate; if (JvmMemoryAllocated > JvmMemoryHighWaterMark) { JvmMemoryHighWaterMark = JvmMemoryAllocated; } #endif #endif } if (loc != NULL && jvm_tag_malloc) { jvm_malloc_total += size; } if (jvm_trace_malloc) { tty->print_cr("|%x| Malloc(%d): total=%d, %s:%d ", loc, size, jvm_malloc_total, file_tail(filename), lineno); } if (jvm_trash_malloc && loc != NULL) { JVM_Memset(loc, 0xab, size); } #ifdef REPORT_LEVEL #if REPORT_LEVEL <= LOG_INFORMATION reportToLog(LOG_INFORMATION, LC_MALLOC, "DEBUG: Requested %d provided %d at 0x%p", numBytesToAllocate, jvmMemoryHdr->size, loc); printAllocation(LOG_INFORMATION, "allocated", filename, lineno); #else (void)filename; /* No-op */ (void)lineno; /* No-op */ #endif #endif return(loc); } /* end of allocating */ } /* end of else */ } /* end of for */ tty->print_cr("DEBUG: Unable to allocate %d bytes", numBytesToAllocate); return((void *)0); }