예제 #1
0
파일: miscd.c 프로젝트: wyat/kbs
int killdir(char *basedir, char *filename)
{
    int fd;
    struct stat st;
    struct fileheader *files, *afile;
    int i;
    int now = (time(NULL) / 86400) % 100;
    int count = 0;
    int deleted = 0;

    strcpy(genbuf1, basedir);
    strcat(genbuf1, "/");
    strcat(genbuf1, filename);
    fd = open(genbuf1, O_RDWR);
    if (fd < 0)
        return 0;
    if (writew_lock(fd, 0, SEEK_SET, 0) < 0) {
        close(fd);
        return 0;
    }
    if (fstat(fd, &st) < 0) {
        un_lock(fd, 0, SEEK_SET, 0);
        close(fd);
        return 0;
    }
    if ((files = (struct fileheader *) malloc(st.st_size)) == NULL) {
        un_lock(fd, 0, SEEK_SET, 0);
        close(fd);
        return 0;
    }
    if (read(fd, files, st.st_size) < 0) {
        free(files);
        un_lock(fd, 0, SEEK_SET, 0);
        close(fd);
        return 0;
    }
    lseek(fd, 0, 0);
    for (i = 0, afile = files; i < st.st_size / sizeof(struct fileheader); i++, afile++) {
    int delta;
    delta=now-afile->accessed[sizeof(afile->accessed) - 1];
    if (delta<0) delta+=100;
        if (delta > DAY_DELETED_CLEAN) {
            strcpy(genbuf1, basedir);
            strcat(genbuf1, "/");
            strcat(genbuf1, afile->filename);
            unlink(genbuf1);
            deleted++;
        } else {
            write(fd, afile, sizeof(struct fileheader));
            count += sizeof(struct fileheader);
        }
    }
    ftruncate(fd, count);
    /*flock(fd, LOCK_EX);*/ /* 又写错了 .. ? */
    un_lock(fd, 0, SEEK_SET, 0);
    free(files);
    close(fd);
    return deleted;
}
예제 #2
0
static int load_highrecord(int level,struct high_record* hr,int myrecord)
{
    int fd,ret;

    bzero(hr,sizeof(*hr));
    if (level==-1) {
    	hr->shortest=-1;
    	return 0;
    }
    if (myrecord!=-1) 
        fd=open(RECORD_FILE,O_RDWR|O_CREAT,0644);
    else
        fd=open(RECORD_FILE,O_RDONLY|O_CREAT,0644);
    	
    if (fd==-1) {
    	bbslog("3error","Box:can't open %s:%s",RECORD_FILE,strerror(errno));
    	return -1;
    }
    
    lseek(fd,sizeof(*hr)*(level-1),SEEK_SET);
    if (myrecord!=-1) 
        readw_lock(fd,0,SEEK_SET,sizeof(*hr)*MAXDATA);
    else
        readw_lock(fd,sizeof(*hr)*(level-1),SEEK_SET,sizeof(*hr));
    read(fd,hr,sizeof(*hr));
    ret=0;
    if (myrecord!=-1) {
    	if (hr->shortest>myrecord||hr->shortest<=0) {
		int i;
		int count;
		struct high_record allrecord[MAXDATA];
		count=0;
		lseek(fd,0,SEEK_SET);
		read(fd,&allrecord,sizeof(*hr)*MAXDATA);
		for (i=0;i<MAXDATA;i++) {
			if (!strcasecmp(allrecord[i].userid,getCurrentUser()->userid))
				count++;
		}
		if (count>20) 
			ret = count;
		else {
    		strcpy(hr->userid,getCurrentUser()->userid);
    		hr->shortest=myrecord;
    		lseek(fd,sizeof(*hr)*(level-1),SEEK_SET);
    		write(fd,hr,sizeof(*hr));
    		ret=1;
		}
    	}
    }
    if (myrecord!=-1) 
        un_lock(fd,0,SEEK_SET,sizeof(*hr)*MAXDATA);
    else
        un_lock(fd,sizeof(*hr)*(level-1),SEEK_SET,sizeof(*hr));
    close(fd);
    return ret;
}
예제 #3
0
파일: test1.c 프로젝트: hechenyu/unix_code
int
main(int argc, char **argv)
{
	int		fd;
	pid_t childpid;

	if ((fd = open("test1.data", O_RDWR | O_CREAT, (mode_t) FILE_MODE)) == -1) {
		fprintf(stderr, "open error for %s: %s\n", "test1.data", strerror(errno));
		exit(1);
	}

	if (read_lock(fd, 0, SEEK_SET, 0) == -1) {		/* parent read locks entire file */
		perror("read_lock error");
		exit(1);
	}
	printf("%s: parent has read lock\n", gf_time());

	if ((childpid = fork()) == -1) {
		perror("fork error");
		exit(1);
	}
	if (childpid == 0) {
			/* 4child */
		if (read_lock(fd, 0, SEEK_SET, 0) == -1) {	/* this should work */
			perror("read_lock error");
			exit(1);
		}
		printf("%s: child has read lock\n", gf_time());
		sleep(2);
		if (un_lock(fd, 0, SEEK_SET, 0) == -1) {
			perror("un_lock error");
			exit(1);
		}
		printf("%s: child releases read lock\n", gf_time());

		if (read_lock(fd, 0, SEEK_SET, 0) == -1) {	/* this should work */
			perror("read_lock error");
			exit(1);
		}
		printf("%s: child has read lock\n", gf_time());
		sleep(2);
		exit(0);
	}

	/* parent */
	sleep(4);
	if (un_lock(fd, 0, SEEK_SET, 0) == -1) {
		perror("un_lock error");
		exit(1);
	}
	printf("%s: parent releases read lock\n", gf_time());
	exit(0);
}
예제 #4
0
enum RECORD_RESULT record_write(struct record_t *record, const char *content, size_t size)
{
    if (NULL == record) {
        fprintf (stderr, "Invalid record in record_flush\n");
        return RECORD_ERROR;
    }

    record_open(record);

    writew_lock(record->fd, 0, SEEK_SET, 0);
    lseek(record->fd, 0, SEEK_END);

    int ret = write(record->fd, content, size);

    un_lock(record->fd, 0, SEEK_SET, 0);

    record_close(record);

    if (-1 == ret) {
        fprintf (stderr, "record_write failed\n");
        return RECORD_ERROR;
    }

    if (debug) fprintf (stderr, "record_write: %s %s\n", record->filename, content);
    return RECORD_SUCCESS;
}
예제 #5
0
main()
{
	char buf[1];
	int fd=open("./test.tmp",O_RDWR);

	buf[1]='c';

	write(fd,buf,1);
	write_lock(fd, -1, SEEK_END, 0);
	write(fd,buf,1);
	un_lock(fd, 0, SEEK_END,0);
	write(fd,buf,1);

	if(fork()==0){
		if(is_write_lockable(fd, -2, SEEK_END, 1))
			puts("the last third is not locked");
		else
			puts("the last third is locked");

		if(is_write_lockable(fd, -1, SEEK_END, 1))
			puts("the last third is not locked");
		else
			puts("the last third is locked");

		if(is_write_lockable(fd, -0, SEEK_END, 1))
			puts("the last third is not locked");
		else
			puts("the last third is locked");

	}
}
/* Returning the sequential record...
Just gotta step ahead through the index file where we gotta ignore deleted records.
db_rewind() essential to be called before this function at initial stage itself */
char *db_nextrec(DB *db, char *key)
{
	char c, *ptr;
	/* Locking the free list where we don't actually read a record in the mid of deletion*/
	if(readw_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
		err_dump("error");
	do
	{
		/* read next sequential index record */
		if(_db_readidx(db, 0) < 0)
		{
			ptr = NULL; /* end of index file --- EOF */
			goto doreturn;
		}
		/* Checking if the key is still blank or empty record */
		ptr = db->idxbuf;
		while((c = *ptr++) != 0 && c = ' ');
		/* skip if it's not blank */
	}
	while(c == 0) /* loop untill a non-empty key is found*/
		if(key != NULL)
			strcpy(key, db->idxbuf); /* return key */
	ptr = _db_readdat(db); /* return pointer to data buffer */
	db->cnt_nextrec++;
doreturn:
	if(un_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
		err_dump("error");
}
/* writing an index record
_db_writedat() is called before this function inorder to set fields datoff and datlen in the database structure where we gotta write index record */
void _db_writeidx(DB *db, const char *key, off_t offset, int whence, off_t ptrval)
{
	struct iovec iov[2];
	char asciiptrlen[PTR_SZ + IDXLEN_SZ + 1];
	int len;
	if((db->ptrval = ptrval) < 0 || ptrval > PTR_MAX)
		err_quit("invalid ptr: %d", ptrval);
	sprintf(db->idxbuf, "%s%c%d%c%d\n", key, SEP, db->datoff, SEP, db->datlen);
	if((len = strlen(sb->idxbuf)) < IDXLEN_MIN || len > IDXLEN_MAX)
		err_dump("invalid length");
	sprintf(asciiptrlen, "%*d%*d", PTR_SZ, ptrval, IDXLEN_SZ, len);
	/* If we are appending, then we gotta lock before doing lseek() and write() in making the two as atomic operation.
	If we are overwriting an existing record, then we don't have to lock */
	if(whence == SEEK_END) /* we are appending, then lock the entire file. */
		if(writew_lock(db->idxfd, 0, SEEK_SET, 0) < 0)
			err_dump("error");
	if((db->idxoff = lseek(db->idxfd, offset, whence)) == -1)
		err_dump("error");
	iov[0].iov_base = asciiptrlen;
	iov[0].iov_len = PTR_SZ + IDXLEN_SZ;
	iov[1].iov_base = db->idxbuf;
	iov[1].iov_len = len;
	if(writev(db->idxfd, &iov[0], 2) != PTR_SZ + IDXLEN_SZ + len)
		err_dump("error");
	if(whence == SEEK_END)
		if(un_lock(db->idxfd, ((db->nhash + 1)*PTR_SZ)+1, SEEK_SET, 0) < 0)
			err_dump("error");
}
예제 #8
0
char *
db_nextrec(DB *db, char *key)
{
    char    c, *ptr;

        /* We read lock the free list so that we don't read
           a record in the middle of its being deleted. */
    if (readw_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
        err_dump("readw_lock error");

    do {
            /* read next sequential index record */
        if (_db_readidx(db, 0) < 0) {
            ptr = NULL;        /* end of index file, EOF */
            goto doreturn;
        }
            /* check if key is all blank (empty record) */
        ptr = db->idxbuf;
        while ( (c = *ptr++) != 0  &&  c == ' ')
            ;    /* skip until null byte or nonblank */
    } while (c == 0);    /* loop until a nonblank key is found */

    if (key != NULL)
        strcpy(key, db->idxbuf);    /* return key */
    ptr = _db_readdat(db);    /* return pointer to data buffer */

    db->cnt_nextrec++;
doreturn:
    if (un_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
        err_dump("un_lock error");

    return(ptr);
}
/* Opening or Creating a database */
DB *db_open(const char *pathname, int oflag, int mode)
{
	DB *db;
	int i, len;
	char asciiptr[PTR_SZ + 1], hash[(NHASH_DEF + 1) * PTR_SZ +2]; /* +2 for newline and NULL */
	struct stat statbuff;
	/* Allocating a Database structure and the buffer it requires. */
	len = strlen(pathname);
	if((db = _db_alloc(len)) == NULL)
		err_dump("error");
	db->oflag = oflag; /* saving a copy of the open flags */
	/* Opening index file */
	strcpy(db->name, pathname);
	strcat(db->name, ".idx");
	if((db->idxfd = open(db->name, oflag, mode)) < 0)
	{
		_db_free(db);
		return(NULL);
	}
	/* Opening data file */
	strcpy(db->name + len, ".dat");
	if((db->datfd = open(db->name, oflag, mode)) < 0)
	{
		_db_free(db);
		return(NULL);
	}
	/* If the database was created, then initialize it */
	if((oflag & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
	{
		/* write lock the entire file and so that, we can stat the file, check it's size & initialize it */
		if(writew_lock(db->idxfd, 0, SEEK_SET, 0) < 0)
			err_dump("error");
		if(fstat(db->idxfd, &statbuff) < 0)
			err_sys("error");
		if(statbuff.st_size==0)
		{
			/* 
			We gotta build a list of (NHASH_DEF + 1) chain ptr with a value of 0.
			The +1 is for free list pointer that precedes the hash table.
			*/
			sprintf(asciiptr, "%*d", PTR_SZ, 0);
			hash[0] = 0;
			for(i=0;i<(NHASH_DEF + 1);i++)
				strcat(hash, asciiptr);
			strcat(hash, "\n");
			i = strlen(hash);
			if(write(db->idxfd, hash, i) != i)
				err_dump("error");
		}
		if(un_lock(db->idxfd, 0, SEEK_SET, 0) < 0)
			err_dump("error");
	}
	db->nhash = NHASH_DEF; /* hash table size */
	db->hashoff = HASH_OFF; /* offset in index file of hash table */
							/* free list ptr always at FREE_OFF */
	db_rewind(db);
	return(db);
}
예제 #10
0
int main(void)
{
   char *strw = "set write lock on region", *strr = "set read lock on region";
   int fd, bytes_count;
   fd = open(test_file, O_RDWR|O_CREAT, 0666);   /* 開啟檔案 */
   if(fd<0) 
      err_exit("Unable to open file");
   for (bytes_count = 0; bytes_count<100; bytes_count++)  /* 寫入資料 */
      write(fd, "A", 1);              
   if (fork()!=0) {     /* 父執行緒 */
      /* 在區域[10-29]設定共享讀鎖 */
      if (SET_LOCK (fd, F_RDLCK, 10, SEEK_SET, 20)<0)
         fprintf(stderr,"%d %s [10-29] failed\n", getpid(),strr);
      else
         fprintf(stderr,"%d %s [10-29] succeed\n",getpid(),strr);
      /* 在區域[40-49]設定互斥寫鎖 */
      if (SET_LOCK (fd, F_WRLCK, 40, SEEK_SET, 10)<0)
         fprintf(stderr,"%d %s [40-49] failed\n", getpid(),strw);
      else
         fprintf(stderr,"%d %s [40-49] succeed \n",getpid(), strw);
      sleep(3);      /* 睡眠3秒以便子執行緒測試鎖 */
      printf("%d close file\n",getpid());
      close(fd);
      exit(EXIT_SUCCESS);
   } else {         /* 子執行緒 */
      pid_t mypid=getpid(); 
      sleep(1);     /* 讓父執行緒先執行 */
      /* 對區域[10-14]設定讀鎖,與父執行緒設定的讀鎖部分重疊,可成功 */
      if (SET_LOCK (fd, F_RDLCK, 10, SEEK_SET, 5)<0) 
         fprintf(stderr,"%d %s [10-14] failed\n", mypid, strr);
      else 
         fprintf(stderr, "%d %s [10-14] succeed\n", mypid, strr);    
      /* 對區域[15-20]加寫鎖,與父執行緒設定的讀鎖部分重疊,不會成功 */    
      if (SET_LOCK (fd, F_WRLCK, 15,SEEK_SET,6)<0) 
         fprintf(stderr,"%d %s [15-20] failed\n", mypid, strw);
      else 
        fprintf(stderr, "%d %s [15-20]\n", mypid, strw);
      /* 對區域[40-49]加讀鎖,與父執行緒設定的寫鎖重疊,不會成功 */
      if (SET_LOCK (fd, F_RDLCK, 40, SEEK_SET, 10)<0) 
         fprintf(stderr,"%d %s [40-49] failed\n", mypid,strr);
      else 
         fprintf(stderr,"%d %s [40-49] succeed\n", mypid, strr);
      /* 對區域[41-60]加寫鎖並等待,與父執行緒設定的寫鎖重疊,等待父執行緒離開後才會成功 */   
      if (SET_LOCK_W(fd, F_WRLCK, 41, SEEK_SET, 20)<0) 
         fprintf(stderr,"%d %s [41-60] succeed\n", mypid, strw);
      else
         fprintf(stderr,"%d %s [41-60] succeed\n", mypid, strw);
      /* 對區域[0-60]解鎖,將同時釋放區域[10-14]的讀鎖和區域[41-60]的寫鎖 */
      if (un_lock (fd,0,SEEK_SET,69)<0) 
         fprintf(stderr,"%d unlock the region [0-69] failed\n", mypid);
      else 
         fprintf(stderr,"%d unlocked the region [0-69] succeed\n", mypid);
      fprintf(stderr,"Process %d end\n", mypid);    
      close(fd);
      exit(EXIT_SUCCESS);
   }
}
예제 #11
0
void Data_Receive_Anl()
{
	static u8 i =0 ;
	if(LOCK)lock();				
	if(UN_LOCK)un_lock();				
		
					printf("					       %d %d %d\r\n",Rc_D.THROTTLE,Rc_D.PITCH,Rc_D.ROLL);
					printf("%d  %.2lf  %.2lf\r\n",Power,Target_x,Target_y);

}
예제 #12
0
void
do_lock(const char *filename) {
	int fd;
	char ch = 'z';
	/* test read lock */
	if((fd = open(filename, O_RDONLY, NULL)) < 0) {
		Perror("open error");
	}
	if(read_lock(fd, 0, SEEK_SET, 1) == -1) {
		Perror("read_lock error");
	} else {
		printf("Process %d set read_lock successfully\n", getpid());
	}
	if(read(fd, &ch, 1) != 1) {
		Perror("read error");
	} else {
		printf("Process %d read %c from file\n", getpid(), ch);
	}
	if(close(fd) == -1) {
		Perror("close error");
	}
	/*test write lock*/
	ch = 'z';
	if((fd = open(filename, O_WRONLY, NULL)) < 0) {
		Perror("open error");
	}
	do {
		if(write_lock(fd,1,SEEK_SET,1) == -1) {
			if(errno != EAGAIN) {
				Perror("write_lock error");
			}
		} else {
			printf("Process %d set write_lock successfully\n", getpid());
			break;
		}
	}while(1);
	if(write(fd, &ch, 1) != 1) {
		Perror("write error");
	}
	sleep(2);
	if(un_lock(fd,1,SEEK_SET,1) == -1) {
		Perror("un_lock error");
	} else {
		printf("Process %d unlock successfully\n", getpid());
	}
	if(close(fd) == -1) {
		Perror("close error");
	}
}
예제 #13
0
void print_msgs(const char *name, int fd) {

	int i;
	for (i = 0; i < 200; i++) {
		if (writew_lock(fd, 0, SEEK_SET, 0) < 0) {
			perror("Unable to acquire lock");
			return;
		}

		write(fd, name, strlen(name));
		write(fd, buf, sizeof(buf)-1);

		un_lock(fd, 0, SEEK_SET, 0);
	}

}
예제 #14
0
파일: fetch.c 프로젝트: no7dw/cpp-learning
char *
db_fetch(DB *db, const char *key)
{
    char    *ptr;

    if (_db_find(db, key, 0) < 0) {
        ptr = NULL;                /* error, record not found */
        db->cnt_fetcherr++;
    } else {
        ptr = _db_readdat(db);    /* return pointer to data */
        db->cnt_fetchok++;
    }
            /* Unlock the hash chain that _db_find() locked */
    if (un_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0)
        err_dump("un_lock error");
    return(ptr);
}
/* Deleting the specified record */
int db_delete(DB *db, const char *key)
{
	int rc;
	if(_db_find(db, key, 1) == 0)
	{
		rc = _db_dodelete(db); /* record found */
		db->cnt_delok++;
	}
	else
	{
		rc = -1; /* not found */
		db->cnt_delerr++;
	}
	if(un_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0)
		err_dump("error");
	return(rc);
}
예제 #16
0
파일: qmail2bbs.c 프로젝트: wyat/kbs
int my_after_post(struct fileheader *fh, char *boardname)
{
	char buf[256];
	int fd, err = 0, nowid = 0;

	if (!strncmp(fh->title, "Re:", 3)) {
		strncpy(fh->title, fh->title + 4, STRLEN);
	}
	setbfile(buf, boardname, DOT_DIR);

	if ((fd = open(buf, O_WRONLY | O_CREAT, 0664)) == -1) {
		err = 1;
	}

	if (!err) {
        writew_lock(fd, 0, SEEK_SET, 0);
		nowid = get_nextid(boardname);
		fh->id = nowid;
		fh->groupid = fh->id;
		fh->reid = fh->id;
#ifdef HAVE_REPLY_COUNT
		fh->replycount = 1;
#endif /* HAVE_REPLY_COUNT */
		set_posttime(fh);
		lseek(fd, 0, SEEK_END);
		if (safewrite(fd, fh, sizeof(fileheader)) == -1) {
			err = 1;
		}
        un_lock(fd, 0, SEEK_SET, 0);
		close(fd);
	}
	if (err) {
		setbfile(buf, boardname, fh->filename);
		unlink(buf);
		return 1;
	}
	updatelastpost(boardname);

	if (fh->id == fh->groupid)
		setboardorigin(boardname, 1);
	setboardtitle(boardname, 1);
	return 0;
}
/* Writing a data record and called by _db_dodelete() and db_store() */
void _db_writedat(DB *db, const char *data, off_t offset, int whence)
{
	struct iovec iov[2];
	static char newline = '\n';
	/* If we are appending, then we gotta lock before doing lseek() and write() in making the two as atomic operation.
	If we are overwriting an existing record, then we don't have to lock */
	if(whence == SEEK_END) /* we are appending, then lock the entire file. */
		if(writew_lock(db->datfd, 0, SEEK_SET, 0) < 0)
			err_dump("error");
	if((db->datoff = lseek(db->datfd, offset, whence)) == -1)
		err_dump("error");
	db->datlen = strlen(data) + 1; /* datlen includes newline */
	iov[0].iov_base = (char *) data;
	iov[0].iov_len = db->datlen - 1;
	iov[1].iov_base = &newline;
	iov[1].iov_len = 1;
	if(writev(db->datfd, &iov[0], 2) != db->datlen)
		err_dump("error");
	if(whence == SEEK_END)
		if(un_lock(db->datfd, 0, SEEK_SET, 0) < 0)
			err_dump("error");
}
/* Try to find a free index record and accompany data record of correct sizes.
We're only called by db_store() */
int _db_findtree(DB *db, int keylen, int datalen)
{
	int rc;
	off_t offset, nextoffset, saveoffset;
	/* locking the free list */
	if(writew_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
		err_dump("error");
	/* reading the free list pointer */
	saveoffset = FREE_OFF;
	offset = _db_readptr(db, saveoffset);
	while(offset != 0)
	{
		nextoffset = _db_readidx(db, offset);
		if(strlen(db->idxbuf) == keylen && db->datlen == datlen)
			break; /* found a match */
		saveoffset = offset;
		offset = nextoffset;
	}
	if(offset == 0)
		rc = -1; /* no match found */
	else
	{
		/* Found a tree record with matching sizes.
			The index record was read in by _db_readidx() above which sets db->ptrval.
			Also, saveoffset points to the chain ptr that pointed to empty record on free list.
			We'll be setting this chain ptr to db->ptrval, which removes empty record from free list
			*/
		_db_writeptr(db, saveoffset, db->ptrval);
		rc = 0;
		/* _db_readidx() set both db->idxoff and db->datoff.
			This is used by the caller, db_store() inorder to write new index record and data record
		*/
	}
	/* Unlocking the free list */
	if(un_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
		err_dump("error");
	return(rc);
}
예제 #19
0
파일: bbslogd.c 프로젝트: xingskycn/kbs
static void flushlog(int signo)
{
    int i;
    for (i = 0; i < sizeof(logconfig) / sizeof(struct taglogconfig); i++) {
        struct taglogconfig *pconf;

        pconf = &logconfig[i];
        if (pconf->fd>=0 && pconf->buf && pconf->bufptr) {
            writew_lock(pconf->fd, 0, SEEK_SET, 0);
            lseek(pconf->fd, 0, SEEK_END);
            write(pconf->fd, pconf->buf, pconf->bufptr);
            pconf->bufptr = 0;
            un_lock(pconf->fd, 0, SEEK_SET, 0);
        }
        if (signo!=-1)
            close(pconf->fd);
    }
    if (signo==-1) return;
#if defined(NEWPOSTLOG) || defined(NEWBMLOG)
	closenewpostlog();
#endif
    exit(0);
}
/* Deleting the current record specified by the database structure.
This function is called by db_delete() and db_store() after the record has been located by _db_find() */
int _db_dodelete(DB *db)
{
	int i;
	char *ptr;
	off_t freeptr, saveptr;
	/* Setting data buffer to all blanks */
	for(ptr = db->datbuf, i = 0; i < db->datlen - 1; i++)
		*ptr++ = ' ';
	*ptr = 0; /*null terminate for _db_writedat()*/
	/* Setting key to blanks */
	ptr = db->idxbuf;
	while(*ptr)
		*ptr++ = ' ';
	/* Locking the free list */
	if(writew_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
		err_dump("error");
	/* Writing the data record with all blanks */
	_db_writedat(db, db->datbuf, db->datoff, SEEK_SET);
	/* Reading the free list pointer.
	It's value becomes the chain ptr field of the deleted index record.
	This means that the deleted  record becomes the head of the free list. */
	freeptr = _db_readptr(db, FREE_OFF);
	/* Save the contents of the index record chain ptr before being re-written by _db_writeidx() */
	saveptr = db->ptrval;
	/* Re-writing the index record, which also re-writes the length of the index record , data offset & data length*/
	_db_writeidx(db, db->idxbuf, db->idxoff, SEEK_SET, freeptr);
	/* Writing the new free list pointer */
	_db_writeptr(db, FREE_OFF, db->idxoff);
	/* Re-writing the chain ptr that pointed to this record being deleted.
	Recalling that _db_find() sets db->ptroff to point to this chain ptr.
	We'll be setting this chain ptr to the contents of the deleted record's chain ptr, saveptr, which can be either zero or not */
	_db_writeptr(db, db->ptroff, saveptr);
	if(un_lock(db->idxfd, FREE_OFF, SEEK_SET, 1) < 0)
		err_dump("error");
	return(0);
}
예제 #21
0
파일: utmp.c 프로젝트: wyat/kbs
void utmp_unlock(int fd)
{
    un_lock(fd, 0, SEEK_SET, 0);
    close(fd);
}
예제 #22
0
static void bcache_unlock(int fd)
{
    un_lock(fd, 0, SEEK_SET, 0);
    bcache_setreadonly(1);
    close(fd);
}
예제 #23
0
파일: bbslogd.c 프로젝트: xingskycn/kbs
static void writelog(struct bbs_msgbuf *msg)
{
    char header[256];
    struct tm *n;
    struct taglogconfig *pconf;
    char ch;

#if defined(NEWPOSTLOG) || defined(NEWBMLOG)
	if(!postlog_start && mysqlclosetime && time(0)-mysqlclosetime>600)
		opennewpostlog();
#endif

#ifdef NEWBMLOG
	if (msg->mtype == BBSLOG_BM){
		char sqlbuf[512];
		struct _new_bmlog * ppl = (struct _new_bmlog *)( &msg->mtext[1]) ;
		int affect;

		if(!postlog_start)
			return;

		if(ppl->value == 0)
			return;

		msg->mtext[0]=0;

		sprintf(sqlbuf, "UPDATE bmlog SET `log%d`=`log%d`+%d WHERE userid='%s' AND bname='%s' AND month=MONTH(CURDATE()) AND year=YEAR(CURDATE()) ;", ppl->type, ppl->type, ppl->value, msg->userid, ppl->boardname );

		if( mysql_real_query(&s,sqlbuf,strlen(sqlbuf)) || (affect=(int)mysql_affected_rows(&s))<0 ){
			mysql_fail ++;
			bbslog("3system","mysql bmlog error:%s",mysql_error(&s));
			if(mysql_fail > 10)
				closenewpostlog();
			return;
		}

		if(affect <= 0){
			sprintf(sqlbuf, "INSERT INTO bmlog (`id`, `userid`, `bname`, `month`, `year`, `log%d` ) VALUES (NULL, '%s', '%s', MONTH(CURDATE()), YEAR(CURDATE()), '%d' );", ppl->type, msg->userid, ppl->boardname, ppl->value);

			if( mysql_real_query( &s, sqlbuf, strlen(sqlbuf) )){
				mysql_fail ++;
				bbslog("3system","mysql bmlog error:%s",mysql_error(&s));
				if(mysql_fail > 10)
					closenewpostlog();
			}else
				mysql_fail = 0;
		}else{
			mysql_fail = 0;
		}

		return;
	}
#endif

#ifdef NEWPOSTLOG
	if (msg->mtype == BBSLOG_POST && postlog_start){

		char newtitle[161];
		char sqlbuf[512];
		struct _new_postlog * ppl = (struct _new_postlog *) ( &msg->mtext[1]) ;
		char newts[20];

		msg->mtext[0]=0;

		mysql_escape_string(newtitle, ppl->title, strlen(ppl->title));

#ifdef NEWSMTH
		sprintf(sqlbuf, "INSERT INTO postlog (`id`, `userid`, `bname`, `title`, `time`, `threadid`, `articleid`, `ip`) VALUES (NULL, '%s', '%s', '%s', '%s', '%d', '%d', '%s');", msg->userid, ppl->boardname, newtitle, tt2timestamp(msg->msgtime, newts), ppl->threadid, ppl->articleid, ppl->ip );
#else
		sprintf(sqlbuf, "INSERT INTO postlog (`id`, `userid`, `bname`, `title`, `time`, `threadid`, `articleid`) VALUES (NULL, '%s', '%s', '%s', '%s', '%d', '%d');", msg->userid, ppl->boardname, newtitle, tt2timestamp(msg->msgtime, newts), ppl->threadid, ppl->articleid );
#endif

		if( mysql_real_query( &s, sqlbuf, strlen(sqlbuf) )){
			mysql_fail ++;
			bbslog("3system","mysql postlog error:%s",mysql_error(&s));
			if(mysql_fail > 10)
				closenewpostlog();
		}else{
			mysql_fail = 0;

			return;
		}
	}

	if (msg->mtype == BBSLOG_POST){
		struct _new_postlog * ppl = (struct _new_postlog *) ( &msg->mtext[1]) ;

		msg->mtype = BBSLOG_USER;

    	if ((msg->mtype < 0) || (msg->mtype > sizeof(logconfig) / sizeof(struct taglogconfig)))
        	return;
    	pconf = &logconfig[msg->mtype-1];

    	if (pconf->fd<0) return;
    	n = localtime(&msg->msgtime);

    	snprintf(header, 256, "[%02u/%02u %02u:%02u:%02u %5lu %lu] %s post '%s' on '%s'\n", n->tm_mon + 1, n->tm_mday, n->tm_hour, n->tm_min, n->tm_sec, (long int) msg->pid, msg->mtype, msg->userid, ppl->title, ppl->boardname);
    	if (pconf->buf) {
        	if ((int) (pconf->bufptr + strlen(header)) <= pconf->bufsize) {
            	strcpy(&pconf->buf[pconf->bufptr], header);
            	pconf->bufptr += strlen(header);
            	return;
        	}
    	}

/*目前log还是分散的,就先lock,seek吧*/
        writew_lock(pconf->fd, 0, SEEK_SET, 0);
    	lseek(pconf->fd, 0, SEEK_END);

    	if (pconf->buf && pconf->bufptr) {
        	write(pconf->fd, pconf->buf, pconf->bufptr);
        	pconf->bufptr = 0;
    	}
        un_lock(pconf->fd, 0, SEEK_SET, 0);

		return;
	}

#endif

    if ((msg->mtype < 0) || (msg->mtype > sizeof(logconfig) / sizeof(struct taglogconfig)))
        return;
    pconf = &logconfig[msg->mtype-1];

    if (pconf->fd<0) return;
    n = localtime(&msg->msgtime);

    ch=msg->mtext[0];
    msg->mtext[0]=0;
    snprintf(header, 256, "[%d-%02u-%02u %02u:%02u:%02u %5lu %lu] %s %c%s", n->tm_year + 1900, n->tm_mon + 1, n->tm_mday, n->tm_hour, n->tm_min, n->tm_sec, (long int) msg->pid, msg->mtype, msg->userid,ch,&msg->mtext[1]);
    if (pconf->buf) {
        if ((int) (pconf->bufptr + strlen(header)) <= pconf->bufsize) {
            strcpy(&pconf->buf[pconf->bufptr], header);
            pconf->bufptr += strlen(header);
            return;
        }
    }

/*目前log还是分散的,就先lock,seek吧*/
    writew_lock(pconf->fd, 0, SEEK_SET, 0);
    lseek(pconf->fd, 0, SEEK_END);

    if (pconf->buf && pconf->bufptr) {
        write(pconf->fd, pconf->buf, pconf->bufptr);
        pconf->bufptr = 0;
    }
    un_lock(pconf->fd, 0, SEEK_SET, 0);
}
/* Storing a record in a database.
Return 0 if okay, Return 1 if record exists and DB_INSERT specified.
Return -1 if record doesn't exist and DB_REPLACE specified.
*/
int db_store(DB *db, const char *key, const char *data, int flag)
{
	int rc, keylen, datlen;
	off_t ptrval;
	keylen = strlen(key);
	datlen = strlen(data) + 1; /* +1 is for newline at the end */
	if(datlen < DATLEN_MIN || datalen > DATLEN_MAX)
		err_dump("invalid data length");
	/* db_find() calculates which hash table this new record goes into(db->chainoff) whether it already exists or not.
	The calls to _db_writeptr() below change the hash table entry for this chain to point to new record.
	This means that the new record is added to the front of the hash chain */
	if(_db_find(db, key, 1) < 0)
	{
		/* record not found*/
		if(flag & DB_REPLACE)
		{
			rc = -1;
			db->cnt_storerr++;
			goto doreturn; /* error --- record doesn't exist */
		}
		/* do_find() locked the hash chain.
			Reading the chain ptr to the first index record on hash chain */
		ptrval = _db_readptr(db, db->chainoff);
		if(_db_findfree(db, keylen, datlen) < 0)
		{
			/* an empty record of the correct record wasn't found.
				we gotta append the new record to the ends of the index and data files */
			_db_writedat(db, data, 0, SEEK_END);
			_db_writeidx(db, key, 0, SEEK_END, ptrval);
			/* db->idxoff was set by _db_writeidx()
			The record goes to the front of the bash chain */
			_db_writeptr(db, db->chainoff, db->idxoff);
			db->cnt_stor1++;
		}
		else
		{
			/* Re-using an empty record
			_db_findtree() removed the record from the free list and set both db->datoff and db->idxoff */
			_db_writedat(db, data, 0, SEEK_END);
			_db_writeidx(db, key, 0, SEEK_END, ptrval);
			/* re-used record goes to the front of the hash chain */
			_db_writeptr(db, db->chainoff, db->idxoff);
			db->cnt_stor2++;
		}
	}
	else
	{
		/* record found */
		if(flag & DB_INSERT)
		{
			rc = 1;
			db->cnt_storerr++;
			goto doreturn; /* error --- record is already in the database */
		}
		/* We are replacing the existing record.
			We know the new key equals the existing key, but also we gotta check if the data records are the same size. */
		if(datlen != db->datlen)
		{
			_db_dodelete(db); /* delete the existing record */
			/* Re-read the chain ptr in the hash table (It may change with the deletion) */
			ptrval = _db_readptr(db, db->chainoff);
			/* Appending new index and data records to end of files */
			_db_writedat(db, data, 0, SEEK_END);
			_db_writeidx(db, key, 0, SEEK_END, ptrval);
			/* new record going to the front of the hash chain */
			_db_writeptr(db, db->chainoff, db->idxoff);
			db->cnt_stor3++;
		}
		else
		{
			/* Same sized data, just replaces data record */
			_db_writedat(db, data, db->datoff, SEEK_SET);
			db->cnt_stor4++;
		}
	}
	rc = 0; /* woo hoo */
doreturn: /* unlock the hash chain that _db_find() locked */
	if(un_lock(db->idxfd, db->chainoff, SEEK_SET, 1) < 0)
		return(rc);
}
예제 #25
0
//
//	Function :
//		start_ispd()
//
//  Arguments       :
//		None
//
//
//	Description :
//		This function checks on ispd configuration and starts
//		the ispd on the local host if it is configured in the
//		server.cfg file.
//
//	Return Values:
//		char **		pointer to an argument list array for use
//					with execv.
//
void
start_ispd( void )
{
	char			command[128];
	int				cmdfd;
	pthread_attr_t	thread_attr;
	int32_t			status;

	// Is an ispd configuration defined in the server.cfg ?

	if ( iserver == NULL || iserver->ispd.location.type == CONFIG_LOCATION_NONE || ispd_type == ISPD_TYPE_DISABLED )
	{
        GisExecuteCmd(GIS_REALM_UP_ALL_CMDID);
		return;
    }

	//
	// code to prevent multiple copies of ispd on one host.
	// Uses advisory locking scheme to insure locking
	// ala Stevens - Advanced Unix Programming - Page 372
	//
	// In this case we want to insure we dont call nullproc
	// on a server that already has an ispd running.
	//

	{
		char	pidfile[MAXPATHLEN];
		char	pid_buf[10];
		int		fd_val;
		int		ispd_fd;

		// Make sure ispd is not already running

		sprintf( pidfile, "%s/%s", "/var/run", ISPD_PID_FILE );

		if ( ( ispd_fd = open( pidfile, O_WRONLY | O_CREAT, 0644 )) < 0 )
		{
			NETDEBUG(	MDEF, NETLOG_DEBUG4,
						("INIT : Error opening pid file, %s\n",
						pidfile ));
		}
		else
		{
			// Try and look the file to see if an active ispd is here on
			// localhost

			if ( write_lock( ispd_fd, 0, SEEK_SET, 0 ) < 0 )
			{
				NETDEBUG(	MDEF,	NETLOG_DEBUG2,
							("INIT : ispd already running exiting\n" ));
				//
				// Startup a thread as an RPC server for the ISPD_PROG 
				// program number and GIS_VERS version number. The client
				// of the service is the local ispd daemon. The service will
				// be called when ever the status of the box changes.
				// A callback routine gis_callback() local to this c file
				// is registered to handle data passed to it. It is defined below.
				//

				pthread_attr_init( &thread_attr );

				pthread_attr_setdetachstate( &thread_attr,
											 PTHREAD_CREATE_DETACHED );

				pthread_attr_setscope( &thread_attr, PTHREAD_SCOPE_SYSTEM );

				if ( (status = pthread_create(	&gis_rpcsvc_thread,
												&thread_attr,
												gis_rpcsvc_init,
												(void*) gis_callback ) ) != 0 )
				{
					NETERROR(	MDEF,
								("start_ispd() : error failed to start "
								"gis_rpcsvc_init() - status %d\n",
								status ));
				}
				return;
			}
			else
			{
				un_lock( ispd_fd, 0, SEEK_SET, 0 );
			}

			close( ispd_fd );
		}
	}

	sys_utils_init();			// Initialize stuff for sys_popen()

	// Add stuff to

	conf_inetd();

	//
	// Startup a thread as an RPC server for the ISPD_PROG program number
	// and GIS_VERS version number. The client of the service is the
	// local ispd daemon. The service will be called when ever the status
	// of the box changes. A callback routine gis_callback() local to this
	// c file is registered to handle data passed to it. It is defined below.
	//

	pthread_attr_init( &thread_attr );
	pthread_attr_setdetachstate( &thread_attr, PTHREAD_CREATE_DETACHED );
	pthread_attr_setscope( &thread_attr, PTHREAD_SCOPE_SYSTEM );

	if ( (status = pthread_create(	&gis_rpcsvc_thread,
							&thread_attr,
							gis_rpcsvc_init,
							(void*) gis_callback ) ) != 0 )
	{
		NETERROR(	MDEF,
					("start_ispd() : error failed to start "
						"gis_rpcsvc_init() - status %d\n",
					status ));
	}

	// Build command to ping nullproc of local rpc service ispd
	// to bring up local ispd

	ping_local_ispd();

	return;
}
예제 #26
0
파일: cnv_register.c 프로젝트: wyat/kbs
int main(int argc, char **argv)
{
    FILE* fin,*fout1,*fout2;
	char genbuf[8][256];
	char* ptr;
	int i;
	struct userec * uc;
	int now;
    int exit = 0,goonsearch = 1;
	char userid[IDLEN+2];

	chdir(BBSHOME);
	
	resolve_ucache();
	resolve_utmp();

    now = time(NULL);
	if((fin = fopen("pre_register","r+")) == NULL)
	{
	    printf("open pre_register file failed.\n");
	    return 0;
	}
	if((fout1 = fopen("pre_register1","w")) == NULL)
	{
	    fclose(fin);
	    printf("open pre_register1 file failed.\n");
	    return 0;
	}
	if((fout2 = fopen("new_register","a")) == NULL)
	{
	    fclose(fin);
		fclose(fout1);
	    printf("open pre_register file failed.\n");
	    return 0;
	}

    writew_lock(fileno(fin), 0, SEEK_SET, 0);
	while(!exit){
	    for(i = 0; i < 8;i++)
		{
            if(fgets(genbuf[i], 256, fin) == NULL){
			    exit = 1;
			    break;
			}
		}
		if(exit == 1)break;
		if(goonsearch){
			strncpy(userid,genbuf[1]+8,IDLEN);
			if((ptr=strchr(userid,'\n')) != NULL)*ptr = 0;
			userid[IDLEN]=0;
			if(getuser(userid,&uc) == 0)
			{
		    	printf("genbuf[1] is %s",genbuf[1]);
		    	printf("%s not found\n",userid);
		    	continue;  //get userid's userec
			}
			if((now - uc->firstlogin) > REGISTER_WAIT_TIME)
			{
            		for(i = 0; i < 8;i++)fputs(genbuf[i],fout2);
			}
			else{
				goonsearch=0;
            			for(i = 0; i < 8;i++)fputs(genbuf[i],fout1);
			}
		}else{
			for(i = 0;i< 8; i++)fputs(genbuf[i],fout1);
		}
    }
//    rewind(fout1);
//    ftruncate(fileno(fin),0);
//    while(fgets(genbuf[0],256,fout1))
//    	fputs(genbuf[0],fin);
    un_lock(fileno(fin), 0, SEEK_SET, 0);
    fclose(fin);
    fclose(fout1);
    fclose(fout2);
	
	f_mv("pre_register1","pre_register");
}
예제 #27
0
파일: mmap_lock.c 프로젝트: leonshao/apue
int main(void)
{
	int		fd;
	int		i, counter;
	void	*area;
	pid_t	pid;

	/*
	 * anonymous memory map for related processes
	 */
	if((area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_SHARED,
			-1, 0)) == MAP_FAILED)
		err_sys("mmap error");

	/* create lock file, such as TELL_WAIT() */
	if ((fd = open("templock", O_RDWR | O_CREAT | O_TRUNC, FILE_MODE)) < 0)
		err_sys("open error");
	if (write(fd, "lock", 4) < 0)
		err_sys("write error");

	/* gets write lock */
	if (writew_lock(fd, 0, SEEK_SET, 0) < 0)
		err_sys("write_lock error");

	if((pid = fork()) < 0)
	{
		err_sys("fork error");
	}
	else if(pid > 0)		/* parent */
	{
		for(i = 0; i < NLOOPS; i += 2)
		{
			if((counter = update((long *)area)) != i)
				err_quit("parent: expected %d, got %d", i, counter);
			printf("parent: counter %d, area %ld\n", counter, *(long *)area);

			if (un_lock(fd, 0, SEEK_SET, 0) < 0)
				err_sys("un_lock error");

			sleep(1);	/* to have child get the lock */

			/* gets write lock */
			if (writew_lock(fd, 0, SEEK_SET, 0) < 0)
				err_sys("writew_lock error");
		}
	}
	else					/* child */
	{
		for(i = 1; i < NLOOPS + 1; i += 2)
		{
			/* gets write lock */
			if (writew_lock(fd, 0, SEEK_SET, 0) < 0)
				err_sys("writew_lock error");

			if((counter = update((long *)area)) != i)
				err_quit("child: expected %d, got %d", i, counter);
			printf("child: counter %d, area %ld\n", counter, *(long *)area);

			if (un_lock(fd, 0, SEEK_SET, 0) < 0)
				err_sys("un_lock error");

			sleep(1);	/* to have parent get the lock */
		}
	}

	return 0;
}
예제 #28
0
 void FileLocks::unlock( size_t unlock_pos )
 {
     un_lock( m_fd_, unlock_pos + 4, SEEK_SET, 1 );
     m_pmutexs_[unlock_pos]->unlock();/// 确保线程锁解锁后,文件锁是释放状态,方便timed_lock处理。
 }
예제 #29
0
        size_t FileLocks::alloc_lock( std::string const & keyname )
        {
            if ( keyname.empty() )
            {
                m_thread_mutex_.lock();

                writew_lock( m_fd_, 0, SEEK_SET, 4 );

                char buff[4 + 1] = { 0 };
                long seqno = 0;
                size_t readlen = 0;
                lseek( m_fd_, 0L, SEEK_SET );
                readlen = read( m_fd_, buff, 4 );
                buff[readlen] = '\0';
                readlen = sscanf( buff, "%ld", &seqno );
                snprintf( buff, sizeof( buff ), "%ld", seqno + 1 );
                lseek( m_fd_, 0L, SEEK_SET );
                write( m_fd_, buff, strlen( buff ) );

                un_lock( m_fd_, 0, SEEK_SET, 4 );

                m_pmutexs_.resize( seqno + 1 );
                m_pmutexs_[seqno] = new boost::mutex;
                //std::cout << alloc_lock id = "  << seqno << " lock addr = " << m_pmutexs_[seqno] << " this = " << this << std::endl;
                m_thread_mutex_.unlock();

                return seqno;
            }
            else/// 命名锁
            {
                m_thread_mutex_.lock();
                writew_lock( m_fd_, 0, SEEK_SET, 4 );

                /// 载入已有的锁
                std::ifstream ifs;
                ifs.open( namelock_cache( "process.filelock" ).string().c_str() );
                std::string line;
                std::getline(ifs, line);
                while (std::getline(ifs, line)) 
                {
                    if (line.empty() || line[0] == '#')
                    {
                        continue;
                    }
                    std::string::size_type p = line.find('\t');
                    if (p == std::string::npos)
                    {
                        continue;
                    }

                    std::string name = line.substr(0, p);
                    long value = atol( line.substr(p + 1).c_str() );
                    if ( name == keyname )
                    {
                        ifs.close();
                        un_lock( m_fd_, 0, SEEK_SET, 4 );
                        m_thread_mutex_.unlock();
                        return value;
                    }
                }
                ifs.close();

                // 没有查到
                char buff[4 + 2] = { 0 };
                long seqno = 0;
                size_t readlen = 0;
                lseek( m_fd_, 0L, SEEK_SET );
                readlen = read( m_fd_, buff, 4 );
                buff[readlen] = '\0';
                readlen = sscanf( buff, "%ld", &seqno );
                snprintf( buff, sizeof( buff ), "%ld\n", seqno + 1 );
                lseek( m_fd_, 0L, SEEK_SET );
                write( m_fd_, buff, strlen( buff ) );

                /// 附加到尾部
                std::ofstream ofs;
                ofs.open( namelock_cache( "process.filelock" ).string().c_str(), std::ios_base::app );
                ofs << keyname << "\t" << seqno << std::endl;
                ofs.close();

                un_lock( m_fd_, 0, SEEK_SET, 4 );

                m_pmutexs_.resize( seqno + 1 );
                m_pmutexs_[seqno] = new boost::mutex;
                //std::cout << alloc_lock id = "  << seqno << " lock addr = " << m_pmutexs_[seqno] << " this = " << this << std::endl;

                m_thread_mutex_.unlock();

                return seqno;
            }
        }
예제 #30
0
static char * get_file_info(char *boardname, int threadid, char *title, char *userid, char *filename, int pic)
{

    char dirfile[256];
    int fd;
    struct fileheader fh;

    setbdir(DIR_MODE_NORMAL, dirfile, boardname);
    if ((fd = open(dirfile, O_RDWR, 0644)) < 0)
        return NULL;

    if (get_records_from_id(fd, threadid, &fh, 1, NULL) == 0) {
        close(fd);
        return NULL;
    }
    close(fd);

#ifdef NEWSMTH
    // pig2532 Feb 2008: ignore topic with FEN flag in top10
    if (fh.accessed[1] & FILE_FEN) {
        printf("skip:%s/%d/%s/%s\n", boardname, fh.id, fh.owner, fh.title);
        return NULL;
    }
#endif /* NEWSMTH */

    if (pic) {
        if (!fh.attachment) {
            return NULL;
        } else {
            // 读取楼主的第一个附件,判断是否为图片,是则输出该图以备缩略之用,否则返回NULL
            char fn[PATHLEN];
            int fd_pic;
            char *src, *dst, *dot;
            off_t size_src, size_dst;
            char *aname, *start;
            long asize;

            setbfile(fn, boardname, fh.filename);
            if ((fd = open(fn, O_RDONLY)) == -1)
                return NULL;
            if (readw_lock(fd, 0, SEEK_SET, 0) == -1) {
                close(fd);
                return NULL;
            }
            if (safe_mmapfile_handle(fd, PROT_READ, MAP_PRIVATE, &src, &size_src) == 0) {
                un_lock(fd, 0, SEEK_SET, 0);
                close(fd);
                return NULL;
            }
            if (!(aname = checkattach(src + fh.attachment, size_src - fh.attachment, &asize, &start)))
                return NULL;

            dot = strrchr(aname, '.');
            // 是否图片?
            if (get_attachment_type_from_ext(dot) != ATTACH_IMG) {
                end_mmapfile(src, size_src, -1);
                un_lock(fd, 0, SEEK_SET, 0);
                close(fd);
                return NULL;
            }
            sprintf(fn, "hotpic/%s_%d", boardname, threadid);
            if ((fd_pic = open(fn, O_RDWR | O_CREAT, 0600)) == -1) {
                end_mmapfile(src, size_src, -1);
                un_lock(fd, 0, SEEK_SET, 0);
                close(fd);
                return NULL;
            }
            ftruncate(fd_pic, asize);
            if (safe_mmapfile_handle(fd_pic, PROT_WRITE, MAP_SHARED, &dst, &size_dst) == 0) {
                close(fd_pic);
                un_lock(fd, 0, SEEK_SET, 0);
                close(fd);
                return NULL;
            }
            printf("HOTPIC: %s_%d\n", boardname, threadid);
            memcpy(dst, start, asize);
            end_mmapfile(dst, size_dst, -1);
            end_mmapfile(src, size_src, -1);
            close(fd_pic);
            un_lock(fd, 0, SEEK_SET, 0);
            close(fd);
        }
    }

    strncpy(title, fh.title, 80);
    title[80]=0;

    strncpy(userid, fh.owner, IDLEN);
    userid[IDLEN]='\0';

    strncpy(filename, fh.filename, FILENAME_LEN);
    filename[FILENAME_LEN]='\0';

    return title;
}