This is db.c in view mode; [Download] [Up]
/* * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved. * * Database access and update */ #include "config.h" #include "db.h" #include <errno.h> import char *master_directory, *db_directory, *db_data_directory, *news_directory; import int db_data_subdirs; export master_header master; #ifdef MALLOC_64K_LIMITATION export group_header **active_groups = NULL; #else export group_header *active_groups = NULL; #endif export group_header **sorted_groups = NULL; export int reread_groups_file = 0; /* nnmaster -G */ export int check_group_access = 0; export data_header db_hdr; export data_dynamic_data db_data; export int32 db_read_counter = 0; /* articles read by db_read_art */ export int32 db_write_counter = 0; /* articles written by db_write_art */ /* * Init access to a group */ export group_header *current_group = NULL; export char group_path_name[FILENAME]; export char *group_file_name = NULL; static char *group_position = NULL; static article_number current_digest_article = 0; init_group(gh) register group_header *gh; { register char *p, *q; current_digest_article = 0; if (gh == NULL) return 0; /* if (gh->master_flag & M_IGNORE_GROUP) return 0; /* OBS */ if (gh == current_group) return 1; current_group = gh; if (gh->group_flag & G_FOLDER) { group_position = NULL; group_file_name = NULL; strcpy(group_path_name, gh->archive_file); return 1; } #ifdef NNTP if (use_nntp && nntp_set_group(gh) < 0) return 0; #endif /* NNTP */ if (group_position == NULL) if (who_am_i == I_AM_MASTER || who_am_i == I_AM_EXPIRE) group_position = group_path_name; else { strcpy(group_path_name, news_directory); group_position = group_path_name + strlen(group_path_name); *group_position++ = '/'; } for (p = group_position, q = gh->group_name; *q; q++) *p++ = (*q == '.') ? '/' : *q; if (who_am_i == I_AM_MASTER) { /* The master will chdir to the group's directory to get */ /* better performance (can use relative path names). */ *p++ = NUL; if (!use_nntp) { if (chdir(news_directory) < 0) sys_error(news_directory); if (chdir(group_path_name) < 0) return 0; } group_file_name = group_path_name; return 1; } /* client */ if (gh->master_flag & M_NO_DIRECTORY) return 0; if (check_group_access && !use_nntp) { *p = NUL; if (file_exist(group_path_name, "dxr") == 0) return 0; } *p++ = '/'; *p = NUL; group_file_name = p; return 1; } /* * Open master & group file; read it in if first open. * * GROUPS file format is: * * One line per group: * <group name> [<space><timestamp>] [<space><options>] <NL> * If <timestamp> is omitted, a timestamp of 0 is used (very old group). * If <group name> is "@", the master entry is ignored. * * <options>: * D Digest all articles in the group * N Never digest articles * @ Bogus group, ignore completely * ! Don't collect this group * * Do not edit the GROUPS file while nnmaster is running. * After editing the groups file (options), run nnmaster -G. */ static FILE *group_file = NULL; open_groups(mode) int mode; { group_file = open_file(relative(db_directory, "GROUPS"), mode); if (group_file != NULL && (mode & OPEN_CREATE)) { fprintf(group_file, "#\n#\tNEVER MODIFY THIS FILE WHILE nnmaster IS RUNNING\n"); fprintf(group_file, "#\n#\tRUN 'nnmaster -G' AFTER MODIFYING THIS FILE\n"); fprintf(group_file, "#\n#\tDO NOT REMOVE OR REORDER ANY LINES IN THIS FILE\n#\n"); } return group_file != NULL; } close_groups() { if (group_file != NULL) { fclose(group_file); group_file = NULL; } } db_append_group(gh) register group_header *gh; { char flags[16], *fp; if (gh->group_name[0] == NUL) { fputc('@', group_file); goto out; } fprintf(group_file, "%s", gh->group_name); if (gh->creation_time > 0) fprintf(group_file, " %ld", (long)(gh->creation_time)); fp = flags; if (gh->master_flag & M_IGNORE_G) *fp++ = '!'; if (gh->master_flag & M_ALWAYS_DIGEST) *fp++ = 'D'; if (gh->master_flag & M_NEVER_DIGEST) *fp++ = 'N'; if (gh->master_flag & M_INCLUDE_OLD) *fp++ = 'O'; if (gh->master_flag & M_AUTO_RECOLLECT) *fp++ = 'R'; if (gh->archive_file != NULL) *fp++ = '>'; if (fp != flags) { *fp++ = NUL; fprintf(group_file, " %s%s", flags, gh->archive_file != NULL ? gh->archive_file : ""); } out: fputc(NL, group_file); } db_rewrite_groups(save_groups, group_list) int save_groups; group_header *group_list; { register group_header *gh; if (save_groups) if (save_old_file(relative(db_directory, "GROUPS"), "~") < 0) sys_error("Cannot rename GROUPS file"); open_groups(OPEN_CREATE|MUST_EXIST); if (group_list != NULL) { for (gh = group_list->next_group; gh != NULL; gh = gh->next_group) db_append_group(gh); } else { Loop_Groups_Header(gh) { db_append_group(gh); } } close_groups(); } static char *mk_archive_file(gh, cp, logerr) register group_header *gh; register char *cp; int logerr; { char *name; while (*cp && (*cp == '>' || isspace(*cp))) cp++; name = cp; while (*cp && !isspace(*cp)) cp++; if (*cp) *cp++ = NUL; if (*name) { gh->archive_file = copy_str(name); if (*name == '/') gh->master_flag |= M_AUTO_ARCHIVE; else { gh->master_flag &= ~M_AUTO_ARCHIVE; if (who_am_i == I_AM_MASTER) if (logerr) log_entry('E', "GROUPS %s >%s: Full path required", gh->group_name, name); else printf("Error in GROUPS: %s >%s: Full path required\n", gh->group_name, name); } } return cp; } db_parse_group(gh, trust_master) register group_header *gh; int trust_master; /* trust what is in the master file */ { char line[256]; register char *cp, *name; int ignore; do { if (fgets(line, 256, group_file) == NULL) return 0; for (cp = line; *cp && isspace(*cp); cp++); } while (*cp == NUL || *cp == '#'); gh->archive_file = NULL; name = cp; if (trust_master) { if (gh->group_name_length == 0) { gh->group_name = ""; return 1; } cp = name + gh->group_name_length; if (*cp == NUL || !isspace(*cp)) sys_error("MASTER/GROUPS conflict: %d/%s", gh->group_num, line); } else { /* parse GROUPS line */ if (*cp == '@') { ignore = 1; gh->group_name_length = 0; gh->group_name = ""; goto ignore_group; } if (gh->group_name_length == 0) { while (*cp && !isspace(*cp)) cp++; gh->group_name_length = cp - name; } else { cp = name + gh->group_name_length; if (*cp == NUL || !isspace(*cp)) { sys_error("MASTER/GROUPS conflict: %d/%s", gh->group_num, line); } } } if (*cp) *cp++ = NUL; if (gh->group_name_length > 0) gh->group_name = copy_str(name); else gh->group_name = ""; if (trust_master) { if (gh->master_flag & M_AUTO_ARCHIVE) { while (*cp && *cp != '>') cp++; if (*cp == '>') cp = mk_archive_file(gh, cp, 1); } return 1; } while (*cp && isspace(*cp)) cp++; if (*cp && isdigit(*cp)) { gh->creation_time = atol(cp); while (*cp && isdigit(*cp)) cp++; } else gh->creation_time = 0; while (*cp && isspace(*cp)) cp++; ignore = 0; gh->master_flag &= ~(M_ALWAYS_DIGEST | M_NEVER_DIGEST | M_AUTO_RECOLLECT | M_AUTO_ARCHIVE); while (*cp) { switch (*cp++) { case ' ': case '\t': case NL: case CR: continue; case 'D': /* Collect this group, digest all articles */ gh->master_flag |= M_ALWAYS_DIGEST; continue; case 'N': /* Collect this group, never digest articles */ gh->master_flag |= M_NEVER_DIGEST; continue; case 'O': /* Ignore -O option for this group */ gh->master_flag |= M_INCLUDE_OLD; continue; case 'R': /* Recollect this group when new articles arrive */ gh->master_flag |= M_AUTO_RECOLLECT; continue; case '>': /* Archive all new articles in gh->archive_file */ cp = mk_archive_file(gh, cp, 0); continue; case '@': /* Bogus GROUP -- ignore completely */ ignore = 1; gh->group_name_length = 0; break; case '!': /* Do not collect this group */ case 'X': ignore = 1; break; case '#': /* comment */ *cp = NUL; break; default: printf("Bad GROUPS flag for %s: `%c'\n", gh->group_name, *--cp); break; } break; } ignore_group: /* G_DONE indicates to master that the group must be cleaned */ if (ignore) { if ((gh->master_flag & M_IGNORE_GROUP) == 0) { gh->master_flag |= M_MUST_CLEAN; log_entry('X', "Group %s ignored", gh->group_name); } gh->master_flag |= M_IGNORE_G; } else { /* was group ignored in GROUPS, but not active before? */ if ((gh->master_flag & M_IGNORE_GROUP) == M_IGNORE_G) { gh->master_flag &= ~M_NO_DIRECTORY; log_entry('X', "Group %s activated", gh->group_name); } gh->master_flag &= ~M_IGNORE_G; } return 1; } /* * Open master & group files; read then in if first open. */ static FILE *master_file = NULL; static int db_sequential = 0; #ifdef APOLLO_DOMAIN_OS static make_master_copy() { char client_path[FILENAME]; int n; strcpy(client_path,relative(db_directory, "CLIENT")); unlink(client_path); if ((n = copy_file(relative(db_directory, "MASTER"), client_path, 0)) < 0) log_entry('R', "Copy of MASTER to CLIENT failed (err=%d)", n); } #endif open_master(mode) int mode; { register group_header *gh; int trust_master; close_master(); #ifdef APOLLO_DOMAIN_OS if (who_am_i != I_AM_MASTER && who_am_i != I_AM_ADMIN) master_file = open_file(relative(db_directory, "CLIENT"), mode|MUST_EXIST); else #endif master_file = open_file(relative(db_directory, "MASTER"), mode|MUST_EXIST); db_sequential = 0; if (mode == OPEN_CREATE) db_sequential = 1; if (mode != OPEN_READ) return; db_read_master(); if (who_am_i != I_AM_MASTER && master.db_lock[0]) { printf("DATABASE LOCKED.\n%s\n", master.db_lock); nn_exit(88); } freeobj(sorted_groups); #ifdef MALLOC_64K_LIMITATION if (active_groups) Loop_Groups_Header(gh) freeobj(gh); #endif freeobj(active_groups); active_groups = NULL; sorted_groups = NULL; db_expand_master(); open_groups(OPEN_READ|MUST_EXIST); trust_master = (who_am_i != I_AM_MASTER || !reread_groups_file); db_sequential = 1; #ifdef MALLOC_64K_LIMITATION Loop_Groups_Number(l_g_index) { gh = newobj(group_header, 1); active_groups[l_g_index] = gh; #else Loop_Groups_Header(gh) { #endif gh->group_num = l_g_index; db_read_group(gh); db_parse_group(gh, trust_master); } db_sequential = 0; close_groups(); sort_groups(); } db_expand_master() { master.free_groups = 20; #ifdef MALLOC_64K_LIMITATION active_groups = resizeobj(active_groups, group_header *, master.number_of_groups + master.free_groups); #else active_groups = resizeobj(active_groups, group_header, master.number_of_groups + master.free_groups); clearobj(active_groups + master.number_of_groups, group_header, master.free_groups); #endif sorted_groups = resizeobj(sorted_groups, group_header *, master.number_of_groups + master.free_groups); } close_master() { if (master_file != NULL) { fclose(master_file); master_file = NULL; } } update_group(gh) group_header *gh; { group_number numg; numg = master.number_of_groups; db_read_master(); master.number_of_groups = numg; if (master.db_lock[0]) return -3; db_read_group(gh); if (gh->master_flag & M_IGNORE_GROUP) return 0; if (gh->master_flag & M_BLOCKED) return -1; return 1; } static sort_gh(g1, g2) group_header **g1, **g2; { return strcmp((*g1)->group_name, (*g2)->group_name); } sort_groups() { register group_header *gh; Loop_Groups_Header(gh) sorted_groups[l_g_index] = gh; quicksort(sorted_groups, master.number_of_groups, group_header *, sort_gh); s_g_first = 0; Loop_Groups_Sorted(gh) if (gh->group_name[0] != NUL) { s_g_first = l_g_index; break; } } group_header *lookup_no_alias(name) char *name; { register i, j, k, t; i = s_g_first; j = master.number_of_groups - 1; while (i <= j) { k = (i + j) / 2; if ( (t=strcmp(name, sorted_groups[k]->group_name)) > 0) i = k+1; else if (t < 0) j = k-1; else return sorted_groups[k]; } return NULL; } group_header *lookup(name) char *name; { register group_header *gh; group_header *gh_na; register int32 n, x; gh = lookup_no_alias(name); if (gh == NULL || (gh->master_flag & M_ALIASED) == 0) return gh; gh_na = gh; x = 16; do { if (--x == 0) { log_entry('R', "Possible alias loop: %s", name); return gh_na; } n = (int32)gh->data_write_offset; /* if alias info is unreliable, return original group which will be ignored anyway */ if (n < 0 || n >= master.number_of_groups) { log_entry('R', "Bad aliasing of %s -> %d", gh->group_name, n); return gh_na; } gh = ACTIVE_GROUP(n); } while (gh->master_flag & M_ALIASED); return gh; } art_collected(gh, art_num) group_header *gh; article_number art_num; { return gh->first_db_article <= art_num && gh->last_db_article >= art_num; } char *db_data_path(namebuf, gh, d_or_x) char *namebuf; group_header *gh; char d_or_x; { register char *cp, *np; if (db_data_directory != NULL) { #ifdef DB_LONG_NAMES sprintf(namebuf, "%s/%s.%c", db_data_directory, gh->group_name, d_or_x); #else if (db_data_subdirs) sprintf(namebuf, "%s/%d/%d.%c", db_data_directory, gh->group_num/100, gh->group_num, d_or_x); else sprintf(namebuf, "%s/%d.%c", db_data_directory, gh->group_num, d_or_x); #endif } else { np = namebuf; /* master chdir to the group's directory */ if (who_am_i != I_AM_MASTER) { for (cp = news_directory; *np = *cp++; np++); *np++ = '/'; for (cp = gh->group_name; *cp; cp++) *np++ = *cp == '.' ? '/' : *cp; *np++ = '/'; } *np++ = '.'; *np++ = 'n'; *np++ = 'n'; *np++ = d_or_x; *np++ = NUL; } return namebuf; } FILE *open_data_file(gh, d_or_x, mode) group_header *gh; char d_or_x; int mode; { FILE *f; char data_file[FILENAME]; db_data_path(data_file, gh, d_or_x); if (mode == -1) { if (unlink(data_file) < 0 && errno != ENOTDIR && errno != ENOENT) log_entry('E', "Cannot unlink %s (errno=%d)", data_file, errno); f = NULL; } else { again: f = open_file(data_file, (mode & ~MUST_EXIST)); if (f != NULL) return f; #ifndef DB_LONG_NAMES if (db_data_subdirs && (mode&0xf) == OPEN_CREATE && errno == ENOENT) { char *s; s = strrchr(data_file, '/'); *s = NUL; if (!file_exist(data_file, "dx")) { if (mkdir(data_file, 0755) < 0) sys_error("Cannot create directory %s", data_file); log_entry('C', "Created directory %s", data_file); *s = '/'; goto again; } *s = '/'; errno = ENOENT; } #endif if (mode & MUST_EXIST) sys_error("%s (%d): cannot open '%c' file (mode=%x, errno=%d)", gh->group_name, (int)(gh->group_num), d_or_x, mode, errno); } return f; } #ifdef NETWORK_DATABASE #define MASTER_FIELDS 5 /* + DB_LOCK_MESSAGE bytes */ #define GROUP_FIELDS 9 #define ARTICLE_FIELDS 10 typedef int32 net_long; #ifdef NETWORK_BYTE_ORDER #define net_to_host(buf, n) #define host_to_net(buf, n) #else static net_to_host(buf, lgt) register net_long *buf; int lgt; { while (--lgt >= 0) { *buf = ntohl(*buf); buf++; } } static host_to_net(buf, lgt) register net_long *buf; int lgt; { while (--lgt >= 0) { *buf = htonl(*buf); buf++; } } #endif /* not NETWORK_BYTE_ORDER */ #endif /* NETWORK_DATABASE */ #define NWDB_MAGIC 0x00190000 /* NN#n <-> NW#n */ db_read_master() { #ifdef NETWORK_DATABASE net_long buf[MASTER_FIELDS]; rewind(master_file); if (fread((char *)buf, sizeof(net_long), MASTER_FIELDS, master_file) != MASTER_FIELDS) goto err; if (fread(master.db_lock, sizeof(char), DB_LOCK_MESSAGE, master_file) != DB_LOCK_MESSAGE) goto err; net_to_host(buf, MASTER_FIELDS); master.db_magic = buf[0] ^ NWDB_MAGIC; master.last_scan = buf[1]; master.last_size = buf[2]; master.number_of_groups = buf[3]; master.db_created = buf[4]; #else rewind(master_file); if (fread((char *)&master, sizeof(master_header), 1, master_file) != 1) goto err; #endif if (master.db_magic != NNDB_MAGIC) sys_error("Database magic number mismatch"); return; err: sys_error("Incomplete MASTER file"); } db_write_master() { #ifdef NETWORK_DATABASE net_long buf[MASTER_FIELDS]; buf[0] = master.db_magic ^ NWDB_MAGIC; buf[1] = master.last_scan; buf[2] = master.last_size; buf[3] = master.number_of_groups; buf[4] = master.db_created; host_to_net(buf, MASTER_FIELDS); rewind(master_file); if (fwrite((char *)buf, sizeof(net_long), MASTER_FIELDS, master_file) != MASTER_FIELDS) goto err; if (fwrite(master.db_lock, sizeof(char), DB_LOCK_MESSAGE, master_file) != DB_LOCK_MESSAGE) goto err; #else rewind(master_file); if (fwrite((char *)&master, sizeof(master_header), 1, master_file) != 1) goto err; #endif fflush(master_file); #ifdef APOLLO_DOMAIN_OS if (who_am_i == I_AM_MASTER) make_master_copy(); #endif return; err: sys_error("Write to MASTER failed"); } db_read_group(gh) register group_header *gh; { #ifdef NETWORK_DATABASE net_long buf[GROUP_FIELDS]; if (!db_sequential) fseek(master_file, (off_t)(MASTER_FIELDS * sizeof(net_long) + DB_LOCK_MESSAGE + GROUP_FIELDS * sizeof(net_long) * gh->group_num), 0); if (fread((char *)buf, sizeof(net_long), GROUP_FIELDS, master_file) != GROUP_FIELDS) goto err; net_to_host(buf, GROUP_FIELDS); gh->first_db_article = buf[0]; gh->last_db_article = buf[1]; gh->index_write_offset = buf[2]; gh->data_write_offset = buf[3]; gh->group_name_length = buf[4]; gh->master_flag = buf[5]; gh->first_a_article = buf[6]; gh->last_a_article = buf[7]; gh->creation_time = buf[8]; #else if (!db_sequential) fseek(master_file, (off_t)(sizeof(master_header) + SAVED_GROUP_HEADER_SIZE(*gh) * gh->group_num), 0); if (fread((char *)gh, SAVED_GROUP_HEADER_SIZE(*gh), 1, master_file) != 1) goto err; #endif return; err: sys_error("Read GROUPS failed"); } db_write_group(gh) register group_header *gh; { #ifdef NETWORK_DATABASE net_long buf[GROUP_FIELDS]; if (!db_sequential) fseek(master_file, (off_t)(MASTER_FIELDS * sizeof(net_long) + DB_LOCK_MESSAGE + GROUP_FIELDS * sizeof(net_long) * gh->group_num), 0); buf[0] = gh->first_db_article; buf[1] = gh->last_db_article; buf[2] = gh->index_write_offset; buf[3] = gh->data_write_offset; buf[4] = gh->group_name_length; buf[5] = gh->master_flag; buf[6] = gh->first_a_article; buf[7] = gh->last_a_article; buf[8] = gh->creation_time; host_to_net(buf, GROUP_FIELDS); if (fwrite((char *)buf, sizeof(net_long), GROUP_FIELDS, master_file) != GROUP_FIELDS) goto err; #else if (!db_sequential) fseek(master_file, (off_t)(sizeof(master_header) + SAVED_GROUP_HEADER_SIZE(*gh) * gh->group_num), 0); if (fwrite((char *)gh, SAVED_GROUP_HEADER_SIZE(*gh), 1, master_file) != 1) goto err; #endif fflush(master_file); #ifdef APOLLO_DOMAIN_OS if (who_am_i == I_AM_MASTER) make_master_copy(); #endif return; err: sys_error("Write GROUPS failed"); } db_read_art(f) FILE *f; { #ifdef NETWORK_DATABASE net_long buf[ARTICLE_FIELDS]; if (fread((char *)buf, sizeof(net_long), ARTICLE_FIELDS, f) != ARTICLE_FIELDS) return 0; net_to_host(buf, ARTICLE_FIELDS); db_hdr.dh_number = buf[0]; db_hdr.dh_date = buf[1]; db_hdr.dh_hpos = buf[2]; db_hdr.dh_lpos = buf[3]; db_hdr.dh_fpos = buf[4]; db_hdr.dh_lines = buf[5]; db_hdr.dh_replies = buf[6]; db_hdr.dh_cross_postings = buf[7]; db_hdr.dh_subject_length = buf[8]; db_hdr.dh_sender_length = buf[9]; #else if (fread((char *)&db_hdr, sizeof(data_header), 1, f) != 1) return 0; #endif if (db_hdr.dh_number < 0) { current_digest_article = db_hdr.dh_number = -db_hdr.dh_number; db_data.dh_type = DH_DIGEST_HEADER; } else if (db_hdr.dh_number == 0) { db_hdr.dh_number = current_digest_article; db_data.dh_type = DH_SUB_DIGEST; } else { current_digest_article = 0; db_data.dh_type = DH_NORMAL; } if (db_hdr.dh_cross_postings) if (fread((char *)db_data.dh_cross, sizeof(cross_post_number), (int)db_hdr.dh_cross_postings, f) != (int)db_hdr.dh_cross_postings) return -1; if (db_hdr.dh_sender_length) if (fread(db_data.dh_sender, sizeof(char), (int)db_hdr.dh_sender_length, f) != db_hdr.dh_sender_length) return -1; db_data.dh_sender[db_hdr.dh_sender_length] = NUL; if (db_hdr.dh_subject_length) if (fread(db_data.dh_subject, sizeof(char), (int)db_hdr.dh_subject_length, f) != db_hdr.dh_subject_length) return -1; db_data.dh_subject[db_hdr.dh_subject_length] = NUL; db_read_counter++; return 1; } db_write_art(f) FILE *f; { #ifdef NETWORK_DATABASE net_long buf[ARTICLE_FIELDS]; #endif article_number art_num = db_hdr.dh_number; switch (db_data.dh_type) { case DH_NORMAL: break; case DH_SUB_DIGEST: db_hdr.dh_number = 0; break; case DH_DIGEST_HEADER: db_hdr.dh_number = -art_num; break; } #ifdef NETWORK_DATABASE buf[0] = db_hdr.dh_number; buf[1] = db_hdr.dh_date; buf[2] = db_hdr.dh_hpos; buf[3] = db_hdr.dh_lpos; buf[4] = db_hdr.dh_fpos; buf[5] = db_hdr.dh_lines; buf[6] = db_hdr.dh_replies; buf[7] = db_hdr.dh_cross_postings; buf[8] = db_hdr.dh_subject_length; buf[9] = db_hdr.dh_sender_length; host_to_net(buf, ARTICLE_FIELDS); if (fwrite((char *)buf, sizeof(net_long), ARTICLE_FIELDS, f) != ARTICLE_FIELDS) return -1; #else if (fwrite((char *)&db_hdr, sizeof(data_header), 1, f) != 1) return -1; #endif if (db_hdr.dh_cross_postings) if (fwrite((char *)db_data.dh_cross, sizeof(cross_post_number), (int)db_hdr.dh_cross_postings, f) != (int)db_hdr.dh_cross_postings) return -1; if (db_hdr.dh_sender_length) if (fwrite(db_data.dh_sender, sizeof(char), (int)db_hdr.dh_sender_length, f) != db_hdr.dh_sender_length) return -1; if (db_hdr.dh_subject_length) if (fwrite(db_data.dh_subject, sizeof(char), (int)db_hdr.dh_subject_length, f) != db_hdr.dh_subject_length) return -1; db_hdr.dh_number = art_num; db_write_counter++; return 1; } off_t get_index_offset(gh, art_num) group_header *gh; article_number art_num; { #ifdef NETWORK_DATABASE return (off_t)((art_num - gh->first_db_article) * sizeof(net_long)); #else return (off_t)((art_num - gh->first_db_article) * sizeof(off_t)); #endif } off_t get_data_offset(gh, art_num) group_header *gh; article_number art_num; { FILE *index; off_t data_offset; if (gh->first_db_article == art_num) return (off_t)0; index = open_data_file(gh, 'x', OPEN_READ); if (index == NULL) return (off_t)(-1); fseek(index, get_index_offset(gh, art_num), 0); if (!db_read_offset(index, &data_offset)) data_offset = (off_t)(-1); fclose(index); return data_offset; } db_read_offset(f, offset) FILE *f; off_t *offset; { #ifdef NETWORK_DATABASE net_long temp; if (fread((char *)&temp, sizeof(net_long), 1, f) != 1) return 0; #ifndef NETWORK_BYTE_ORDER temp = ntohl(temp); #endif *offset = temp; #else if (fread((char *)offset, sizeof(off_t), 1, f) != 1) return 0; #endif return 1; } db_write_offset(f, offset) FILE *f; off_t *offset; { #ifdef NETWORK_DATABASE net_long temp; temp = *offset; #ifndef NETWORK_BYTE_ORDER temp = htonl(temp); #endif if (fwrite((char *)&temp, sizeof(net_long), 1, f) != 1) return 0; #else if (fwrite((char *)offset, sizeof(off_t), 1, f) != 1) return 0; #endif return 1; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.