Skip to content
Snippets Groups Projects
Select Git revision
  • dailybuild_linux-x64
  • dailybuild_win32
  • master default protected
  • sqlite
  • rip_abstraction
  • dailybuild_macos-armv8
  • dd_file_lister_filanem_in_desc_color
  • mode7
  • dd_msg_reader_are_you_there_warning_improvement
  • c23-playing
  • syncterm-1.3
  • syncterm-1.2
  • test-build
  • hide_remote_connection_with_telgate
  • 638-can-t-control-c-during-a-file-search
  • add_body_to_pager_email
  • mingw32-build
  • cryptlib-3.4.7
  • ree/mastermind
  • new_user_dat
  • sbbs320d
  • syncterm-1.6
  • syncterm-1.5
  • syncterm-1.4
  • sbbs320b
  • syncterm-1.3
  • syncterm-1.2
  • syncterm-1.2rc6
  • syncterm-1.2rc5
  • push
  • syncterm-1.2rc4
  • syncterm-1.2rc2
  • syncterm-1.2rc1
  • sbbs319b
  • sbbs318b
  • goodbuild_linux-x64_Sep-01-2020
  • goodbuild_win32_Sep-01-2020
  • goodbuild_linux-x64_Aug-31-2020
  • goodbuild_win32_Aug-31-2020
  • goodbuild_win32_Aug-30-2020
40 results

smbfile.c

Blame
  • smbfile.c 13.64 KiB
    /* Synchronet message base (SMB) FILE stream and FileBase routines  */
    
    /****************************************************************************
     * @format.tab-size 4		(Plain Text/Source Code File Header)			*
     * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
     *																			*
     * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
     *																			*
     * This library 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.					*
     * See the GNU Lesser General Public License for more details: lgpl.txt or	*
     * http://www.fsf.org/copyleft/lesser.html									*
     *																			*
     * For Synchronet coding style and modification guidelines, see				*
     * http://www.synchro.net/source.html										*
     *																			*
     * Note: If this box doesn't appear square, then you need to fix your tabs.	*
     ****************************************************************************/
    
    #include "smblib.h"
    
    int smb_feof(FILE* fp)
    {
    	return(feof(fp));
    }
    
    int smb_ferror(FILE* fp)
    {
    	return(ferror(fp));
    }
    
    int smb_fflush(FILE* fp)
    {
    	return(fflush(fp));
    }
    
    int smb_fgetc(FILE* fp)
    {
    	return(fgetc(fp));
    }
    
    int smb_fputc(int ch, FILE* fp)
    {
    	return(fputc(ch,fp));
    }
    
    int smb_fseek(FILE* fp, off_t offset, int whence)
    {
    	return(fseeko(fp,offset,whence));
    }
    
    off_t smb_ftell(FILE* fp)
    {
    	return(ftello(fp));
    }
    
    off_t smb_fgetlength(FILE* fp)
    {
    	return(filelength(fileno(fp)));
    }
    
    int smb_fsetlength(FILE* fp, off_t length)
    {
    	return(chsize(fileno(fp),length));
    }
    
    void smb_rewind(FILE* fp)
    {
    	rewind(fp);
    }
    
    void smb_clearerr(FILE* fp)
    {
    	clearerr(fp);
    }
    
    size_t smb_fread(smb_t* smb, void* buf, size_t bytes, FILE* fp)
    {
    	size_t ret;
    	time_t start=0;
    
    	while(1) {
    		if((ret=fread(buf,sizeof(char),bytes,fp))==bytes)
    			return(ret);
    		if(feof(fp) || (get_errno()!=EDEADLOCK && get_errno()!=EACCES))
    			return(ret);
    		if(!start)
    			start=time(NULL);
    		else
    			if(time(NULL)-start>=(time_t)smb->retry_time)
    				break;
    		SLEEP(smb->retry_delay);
    	}
    	return(ret);
    }
    
    #if defined(__BORLANDC__)
    	#pragma argsused
    #endif
    
    size_t smb_fwrite(smb_t* smb, const void* buf, size_t bytes, FILE* fp)
    {
    	return(fwrite(buf,1,bytes,fp));
    }
    
    /****************************************************************************/
    /* Opens a non-shareable file (FILE*) associated with a message base		*/
    /* Retries for retry_time number of seconds									*/
    /* Return 0 on success, non-zero otherwise									*/
    /****************************************************************************/
    int smb_open_fp(smb_t* smb, FILE** fp, int share)
    {
    	int 	file;
    	char	path[MAX_PATH+1];
    	char*	ext;
    	time_t	start=0;
    
    	if(fp==&smb->shd_fp)
    		ext="shd";
    	else if(fp==&smb->sid_fp)
    		ext="sid";
    	else if(fp==&smb->sdt_fp)
    		ext="sdt";
    	else if(fp==&smb->sda_fp)
    		ext="sda";
    	else if(fp==&smb->sha_fp)
    		ext="sha";
    	else if(fp==&smb->hash_fp)
    		ext="hash";
    	else {
    		safe_snprintf(smb->last_error,sizeof(smb->last_error)
    			,"%s opening %s: Illegal FILE* pointer argument: %p", __FUNCTION__
    			,smb->file, fp);
    		return(SMB_ERR_OPEN);
    	}
    
    	if(*fp!=NULL)	/* Already open! */
    		return(SMB_SUCCESS);
    
    	SAFEPRINTF2(path,"%s.%s",smb->file,ext);
    
    	while(1) {
    		if((file=sopen(path,O_RDWR|O_CREAT|O_BINARY,share,DEFFILEMODE))!=-1)
    			break;
    		if(get_errno()!=EACCES && get_errno()!=EAGAIN) {
    			safe_snprintf(smb->last_error,sizeof(smb->last_error)
    				,"%s %d '%s' opening %s", __FUNCTION__
    				,get_errno(),STRERROR(get_errno()),path);
    			return(SMB_ERR_OPEN);
    		}
    		if(!start)
    			start=time(NULL);
    		else
    			if(time(NULL)-start>=(time_t)smb->retry_time) {
    				safe_snprintf(smb->last_error,sizeof(smb->last_error)
    					,"%s timeout opening %s (errno=%d, retry_time=%lu)", __FUNCTION__
    					,path, get_errno(), (ulong)smb->retry_time);
    				return(SMB_ERR_TIMEOUT); 
    			}
    		SLEEP(smb->retry_delay);
    	}
    	if((*fp=fdopen(file,"r+b"))==NULL) {
    		safe_snprintf(smb->last_error,sizeof(smb->last_error)
    			,"%s %d '%s' fdopening %s (%d)", __FUNCTION__
    			,get_errno(),STRERROR(get_errno()),path,file);
    		close(file);
    		return(SMB_ERR_OPEN); 
    	}
    	setvbuf(*fp,NULL,_IOFBF, 2*1024);
    	return(SMB_SUCCESS);
    }
    
    /****************************************************************************/
    /****************************************************************************/
    void smb_close_fp(FILE** fp)
    {
    	if(fp!=NULL) {
    		if(*fp!=NULL)
    			fclose(*fp);
    		*fp=NULL;
    	}
    }
    
    /****************************************************************************/
    /* maxlen includes the NUL terminator										*/
    /****************************************************************************/
    char* smb_fileidxname(const char* filename, char* buf, size_t maxlen)
    {
    	size_t fnlen = strlen(filename);
    	char* ext = getfext(filename);
    	if(ext != NULL) {
    		size_t extlen = strlen(ext);
    		if(extlen >= maxlen - 1) {
    			strncpy(buf, filename, maxlen);
    			buf[maxlen - 1] = '\0';
    		}
    		else {
    			fnlen -= extlen;
    			if(fnlen > (maxlen - 1) - extlen)
    				fnlen = (maxlen - 1) - extlen;
    			safe_snprintf(buf, maxlen, "%-.*s%s", (int)fnlen, filename, ext);
    		}
    	} else {	/* no extension */
    		strncpy(buf, filename, maxlen);
    		buf[maxlen - 1] = '\0';
    	}
    	return buf;
    }
    
    /****************************************************************************/
    /* Find file in index via either/or:										*/
    /* -  CASE-INSENSITIVE 'filename' search through index (no wildcards)		*/
    /* -  file content size and hash details found in 'file'					*/
    /****************************************************************************/
    int smb_findfile(smb_t* smb, const char* filename, smbfile_t* file)
    {
    	long offset = 0;
    	smbfile_t* f = file;
    	smbfile_t file_ = {0};
    	if(f == NULL)
    		f = &file_;
    	uint64_t fsize;
    	char fname[SMB_FILEIDX_NAMELEN + 1] = "";
    	if(filename != NULL)
    		smb_fileidxname(filename, fname, sizeof(fname));
    
    	if(smb->sid_fp == NULL) {
    		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s msgbase not open", __FUNCTION__);
    		return SMB_ERR_NOT_OPEN;
    	}
    	f->dir = smb->dirnum;
    	rewind(smb->sid_fp);
    	while(!feof(smb->sid_fp)) {
    		fileidxrec_t fidx;
    
    		if(smb_fread(smb, &fidx, sizeof(fidx), smb->sid_fp) != sizeof(fidx))
    			break;
    
    		f->idx_offset = offset++;
    
    		if(filename != NULL) {
    			if(stricmp(fidx.name, fname) != 0)
    				continue;
    			f->file_idx = fidx;
    			return SMB_SUCCESS;
    		}
    
    		if(file == NULL)
    			continue;
    
    		fsize = smb_getfilesize(&f->idx);
    		if((f->file_idx.hash.flags & SMB_HASH_MASK) != 0 || fsize > 0) {
    			if(fsize > 0 && fsize != smb_getfilesize(&fidx.idx))
    				continue;
    			if((f->file_idx.hash.flags & SMB_HASH_CRC16) && f->file_idx.hash.data.crc16 != fidx.hash.data.crc16)
    				continue;
    			if((f->file_idx.hash.flags & SMB_HASH_CRC32) && f->file_idx.hash.data.crc32 != fidx.hash.data.crc32)
    				continue;
    			if((f->file_idx.hash.flags & SMB_HASH_MD5)
    				&& memcmp(f->file_idx.hash.data.md5, fidx.hash.data.md5, sizeof(fidx.hash.data.md5)) !=0)
    				continue;
    			if((f->file_idx.hash.flags & SMB_HASH_SHA1)
    				&& memcmp(f->file_idx.hash.data.sha1, fidx.hash.data.sha1, sizeof(fidx.hash.data.sha1)) !=0)
    				continue;
    			f->file_idx = fidx;
    			return SMB_SUCCESS;
    		}
    	}
    	return SMB_ERR_NOT_FOUND;
    }
    
    /****************************************************************************/
    /****************************************************************************/
    int smb_loadfile(smb_t* smb, const char* filename, smbfile_t* file, enum file_detail detail)
    {
    	int result;
    
    	memset(file, 0, sizeof(*file));
    
    	if((result = smb_findfile(smb, filename, file)) != SMB_SUCCESS)
    		return result;
    
    	return smb_getfile(smb, file, detail);
    }
    
    /****************************************************************************/
    /****************************************************************************/
    int smb_getfile(smb_t* smb, smbfile_t* file, enum file_detail detail)
    {
    	int result;
    
    	file->name = file->file_idx.name;
    	file->hdr.when_written.time = file->idx.time;
    	if(detail > file_detail_index) {
    		if((result = smb_getmsghdr(smb, file)) != SMB_SUCCESS)
    			return result;
    		if(detail >= file_detail_extdesc)
    			file->extdesc = smb_getmsgtxt(smb, file, GETMSGTXT_BODY_ONLY);
    		if(detail >= file_detail_metadata)
    			file->metadata = smb_getmsgtxt(smb, file, GETMSGTXT_TAIL_ONLY);
    	}
    	file->dir = smb->dirnum;
    
    	return SMB_SUCCESS;
    }
    
    /****************************************************************************/
    /* Writes both header and index information for file 'file'                 */
    /* Like smb_putmsg() but doesn't (re)-initialize index (idx)				*/
    /****************************************************************************/
    int smb_putfile(smb_t* smb, smbfile_t* file)
    {
    	int result;
    
    	if((result = smb_putmsghdr(smb, file))!=SMB_SUCCESS)
    		return result;
    
    	return smb_putmsgidx(smb, file);
    }
    
    /****************************************************************************/
    /****************************************************************************/
    void smb_freefilemem(smbfile_t* file)
    {
    	smb_freemsgmem(file);
    }
    
    /****************************************************************************/
    /****************************************************************************/
    int smb_addfile(smb_t* smb, smbfile_t* file, int storage, const char* extdesc, const char* metadata, const char* path)
    {
    	if(file->name == NULL || *file->name == '\0') {
    		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s missing name", __FUNCTION__);
    		return SMB_ERR_HDR_FIELD;
    	}
    	if(smb_findfile(smb, file->name, NULL) == SMB_SUCCESS) {
    		safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s duplicate name found: %s", __FUNCTION__, file->name);
    		return SMB_DUPE_MSG;
    	}
    	if(path != NULL) {
    		file->size = flength(path);
    		file->hdr.when_written.time = (uint32_t)fdate(path);
    		if(!(smb->status.attr & SMB_NOHASH) && file->file_idx.hash.flags == 0)
    			file->file_idx.hash.flags = smb_hashfile(path, file->size, &file->file_idx.hash.data);
    	}
    	file->hdr.attr |= MSG_FILE;
    	file->hdr.type = SMB_MSG_TYPE_FILE;
    	return smb_addmsg(smb, file, storage, SMB_HASH_SOURCE_NONE, XLAT_NONE
    		,/* body: */(const uchar*)extdesc, /* tail: */(const uchar*)metadata);
    }
    
    /****************************************************************************/
    /* Like smb_addfile(), except 'metadata' is a str_list_t: 'list'			*/
    /****************************************************************************/
    int smb_addfile_withlist(smb_t* smb, smbfile_t* file, int storage, const char* extdesc, str_list_t list, const char* path)
    {
    	char* metadata = NULL;
    	int result;
    
    	if(list != NULL && *list != NULL) {
    		size_t size = strListCount(list) * 1024;
    		metadata = calloc(1, size);
    		if(metadata == NULL)
    			return SMB_ERR_MEM;
    		strListCombine(list, metadata, size - 1, "\r\n");
    	}
    	result = smb_addfile(smb, file, storage, extdesc, metadata, path);
    	free(metadata);
    	return result;
    }
    
    /****************************************************************************/
    /****************************************************************************/
    int smb_renewfile(smb_t* smb, smbfile_t* file, int storage, const char* path)
    {
    	int result;
    	if((result = smb_removefile(smb, file)) != SMB_SUCCESS)
    		return result;
    	return smb_addfile(smb, file, storage, file->extdesc, file->metadata, path);
    }
    
    /****************************************************************************/
    /****************************************************************************/
    int smb_removefile(smb_t* smb, smbfile_t* file)
    {
    	int result;
    	int removed = 0;
    	char fname[SMB_FILEIDX_NAMELEN + 1] = "";
    
    	if(!smb->locked && smb_locksmbhdr(smb) != SMB_SUCCESS)
    		return SMB_ERR_LOCK;
    
    	file->hdr.attr |= MSG_DELETE;
    	if((result = smb_putmsghdr(smb, file)) != SMB_SUCCESS) {
    		smb_unlocksmbhdr(smb);
    		return result;
    	}
    	if((result = smb_getstatus(smb)) != SMB_SUCCESS) {
    		smb_unlocksmbhdr(smb);
    		return result;
    	}
    	if((result = smb_open_ha(smb)) != SMB_SUCCESS) {
    		smb_unlocksmbhdr(smb);
    		return result;
    	}
    	if((result = smb_open_da(smb)) != SMB_SUCCESS) {
    		smb_unlocksmbhdr(smb);
    		return result;
    	}
    	result = smb_freemsg(smb, file);
    	smb_close_ha(smb);
    	smb_close_da(smb);
    
    	// Now remove from index:
    	smb_fileidxname(file->name, fname, sizeof(fname));
    	if(result == SMB_SUCCESS) {
    		rewind(smb->sid_fp);
    		fileidxrec_t* fidx = malloc(smb->status.total_files * sizeof(*fidx));
    		if(fidx == NULL) {
    			smb_unlocksmbhdr(smb);
    			return SMB_ERR_MEM;
    		}
    		if(fread(fidx, sizeof(*fidx), smb->status.total_files, smb->sid_fp) != smb->status.total_files) {
    			free(fidx);
    			smb_unlocksmbhdr(smb);
    			return SMB_ERR_READ;
    		}
    		rewind(smb->sid_fp);
    		for(uint32_t i = 0; i < smb->status.total_files; i++) {
    			if(stricmp(fidx[i].name, fname) == 0) {
    				removed++;
    				continue;
    			}
    			if(fwrite(fidx + i, sizeof(*fidx), 1, smb->sid_fp) != 1) {
    				safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s re-writing index"
    					,__FUNCTION__);
    				result = SMB_ERR_WRITE;
    				break;
    			}
    		}
    		free(fidx);
    		if(result == SMB_SUCCESS) {
    			if(removed < 1) {
    				safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s name not found: %s"
    					,__FUNCTION__, fname);
    				result = SMB_ERR_NOT_FOUND;
    			} else {
    				fflush(smb->sid_fp);
    				smb->status.total_files -= removed;
    				if(chsize(fileno(smb->sid_fp), smb->status.total_files * sizeof(*fidx)) != 0) {
    					safe_snprintf(smb->last_error, sizeof(smb->last_error), "%s error %d truncating index"
    						,__FUNCTION__, errno);
    					result = SMB_ERR_DELETE;
    				} else
    					result = smb_putstatus(smb);
    			}
    		}
    	}
    
    	smb_unlocksmbhdr(smb);
    	return result;
    }
    
    uint64_t smb_getfilesize(idxrec_t* idx)
    {
    	return ((uint64_t)idx->size) | (((uint64_t)idx->size_ext) << 32);
    }
    
    int smb_setfilesize(idxrec_t* idx, uint64_t size)
    {
    	if(size > 0xffffffffffffULL)
    		return SMB_ERR_FILE_LEN;
    
    	idx->size = (uint32_t)size;
    	idx->size_ext = (uint16_t)(size >> 32);
    
    	return SMB_SUCCESS;
    }