Patch: Elm ME+ 2.5 PLalpha63 -> Elm ME+ 2.5 PLalpha64 [2/4] (2/5)
From
Kari Hurtta@21:1/5 to
All on Tue Jul 2 20:52:17 2024
[continued from previous message]
+ entry_same_file =
+ ( isoff(entry->entry_flags,LAST_READ_have_st_ino) &&
+ isoff(entry_flags,LAST_READ_have_st_ino) )
+ ||
+ ( ison(entry->entry_flags,LAST_READ_have_st_ino) &&
+ ison(entry_flags,LAST_READ_have_st_ino) &&
+ st_ino == entry->st_ino );
+ }
+
+ if ((time_t) -1 != now && last_read > now) {
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %Q: %zu -- timestamp in future, last_read = %d > now = %d\n",
+ filename,lineno,entry_name, idx,
+ last_read,now));
+
+ } else if (ison(entry->entry_flags,LAST_READ_old) ||
+ isoff(entry->entry_flags,LAST_READ_valid) || +
+ ( entry_same_file &&
+ entry->last_read < last_read) ||
+
+ ( isoff(entry->entry_flags,LAST_READ_modified) &&
+ entry->last_read < last_read)
+ ) {
+
+ /* Update from disk */
+
+ entry->entry_flags = entry_flags |
+ ( entry->entry_flags &
+ LAST_READ_flag );
+
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %Q: %zu -- %s",
+ filename,lineno,entry_name, idx,
+ ison(entry->entry_flags,LAST_READ_valid) ?
+ "updating" : "setting"));
+
+ if (ison(entry->entry_flags,LAST_READ_valid)) {
+ if (entry->last_read != last_read) {
+ DPRINT(Debug,14,(&Debug, " last read = %d -> %d",
+ entry->last_read,last_read));
+ }
+
+ if (ison(entry_flags,LAST_READ_have_st_ino) && + entry->st_ino != st_ino) {
+ DPRINT(Debug,14,(&Debug, " st_ino = %lu -> %lu",
+ (unsigned long)entry->st_ino,
+ (unsigned long)st_ino));
+ }
+ } else {
+ DPRINT(Debug,14,(&Debug, " last read = %d",
+ last_read));
+
+ if (ison(entry_flags,LAST_READ_have_st_ino)) { + DPRINT(Debug,14,(&Debug, " st_ino = %lu",
+ (unsigned long)st_ino));
+ }
+ }
+
+ if (comment_len > 0) {
+ comment[comment_len] = '\0';
+
+ DPRINT(Debug,14,(&Debug, " comment = %.*s",
+ comment_len,comment));
+ }
+
+ DPRINT(Debug,14,(&Debug,"\n"));
+
+ entry->last_read = last_read;
+ entry->st_ino = st_ino;
+
+ } else {
+
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %Q: %zu -- skipping update from disk, %s\n",
+ filename,lineno,entry_name, idx,
+ entry_same_file ? "is same file" : "not same file"));
+ }
+
+ /* lineno is incremented later */
+ } else {
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %Q: newline expected\n",
+ filename,lineno,entry_name));
+
+ if (suggest_rewrite)
+ (*suggest_rewrite)++;
+
+ goto skip_line;
+ }
+
+ } else {
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %Q: Skipping line\n",
+ filename,lineno,entry_name));
+
+ skip_line:
+
+ while (EOF != c && '\n' != c)
+ c = fgetc(f);
+
+ }
+
+ /* Decrements refcount */
+ free_last_read_entry(& res.last_read_entry);
+
+
+ } else {
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %Q: search_sort_list_item did not set last_read_entry\n",
+ filename,lineno,entry_name));
+ goto fail_line;
+ }
+
+ } else {
+
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %Q: search_sort_list_item failed to create item\n",
+ filename,lineno,entry_name));
+
+ fail_line:
+ if (suggest_rewrite)
+ (*suggest_rewrite)++;
+
+ end_line:
+ while (EOF != c && '\n' != c)
+ c = fgetc(f);
+ }
+
+ switch (c) {
+ case EOF:
+
+ if (feof(f)) {
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: Unexpect end of file\n",
+ filename,lineno));
+ }
+
+ if (ferror(f)) {
+ int err UNUSED_VAROK = errno;
+
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %d: %s\n",
+ filename,lineno,strerror(err)));
+ }
+ break;
+
+ case '\n':
+ lineno++;
+ break;
+ }
+ }
+
+ if (entry_name) {
+ free(entry_name);
+ entry_name = NULL;
+ }
+ entry_name_alloced = 0;
+
+ if (cache_file) {
+
+ if (! stat_last_read_cache(filename,f,cache_file)) {
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: stat %s failed\n",
+ filename));
+ ret = 0;
+ goto fail;
+ }
+ }
+
+ cache_len = sort_list_len(* cache_entries);
+
+ if (feof(f)) {
+
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %zu items\n",
+ filename,cache_len));
+
+ if (cache_len > 0) {
+ size_t i = cache_len -1;
+ size_t deleted = 0;
+ size_t valid = 0;
+ size_t purge = 0;
+ size_t modified = 0;
+
+ while (1) {
+ union sort_item res;
+
+ res.last_read_entry = NULL;
+
+ /* Increments refcount */
+ get_sort_list_item(* cache_entries,sort_list_get_normal,i,
+ &res);
+
+ if (res.last_read_entry) {
+ struct last_read_entry * entry;
+
+ if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,
+ "parse_last_read_cache",
+ "Bad magic type (last_read_entry)",0);
+
+ entry = res.last_read_entry;
+
+ if (ison(entry->entry_flags,LAST_READ_purge))
+ purge++;
+ if (ison(entry->entry_flags,LAST_READ_valid))
+ valid++;
+ if (ison(entry->entry_flags,LAST_READ_modified))
+ modified++;
+
+ if (isoff(entry->entry_flags,LAST_READ_valid) ||
+ (ison(entry->entry_flags,LAST_READ_purge) &&
+ isoff(entry->entry_flags,LAST_READ_modified))) {
+
+ free_last_read_entry(& res.last_read_entry);
+
+ /* Increments refcount */
+ get_sort_list_item(* cache_entries,sort_list_get_remove,i,
+ &res);
+
+ if (res.last_read_entry) {
+ struct last_read_entry * entry;
+
+ if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,
+ "parse_last_read_cache",
+ "Bad magic type (last_read_entry)",0);
+
+ entry = res.last_read_entry;
+
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: #%zu folder_sys=%s - deleted\n",
+ i,entry->folder_sys));
+
+
+ deleted++;
+ }
+
+
+
+ } else
+ clearit(entry->entry_flags,LAST_READ_purge);
+
+ if (res.last_read_entry)
+ free_last_read_entry(& res.last_read_entry);
+ }
+
+ if (i > 0)
+ i--;
+ else
+ break;
+ }
+
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: %zu valid, %zu flagged purge, %zu modified items - %zu deleted.\n",
+ filename,valid,purge,modified,deleted));
+ }
+
+ ret = 1;
+ } else {
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache: %s: All items not readed\n",
+ filename));
+ }
+
+ fail:
+ DPRINT(Debug,14,(&Debug,
+ "parse_last_read_cache=%d\n",
+ ret));
+
+ return ret;
+ }
+
+
+
+ static enum quote_name_res {
+ quote_name_bad = -1 /* Bad name */,
+ quote_name_no = 0 /* do not quote */,
+ quote_name_needed
+
+ } quote_name P_((const char *folder_sys));
+ static enum quote_name_res quote_name(folder_sys)
+ const char *folder_sys;
+ {
+ const char * c;
+
+ enum quote_name_res ret = quote_name_no;
+
+
+ if (! folder_sys[0])
+ return quote_name_bad;
+
+ if ('#' == folder_sys[0])
+ ret = quote_name_needed;
+
+ for (c = folder_sys; *c; c++) {
+
+ switch (*c) {
+
+ case '\n':
+ return quote_name_bad;
+
+ case '"':
+ case '\\':
+ ret = quote_name_needed;
+ break;
+
+ case '\r':
+ return quote_name_bad;
+
+ case '/':
+
+ /* / is only allowed on absolute paths */
+
+ if ('/' != folder_sys[0])
+ return quote_name_bad;
+
+ break;
+
+ default:
+ if (whitespace(*c))
+ ret = quote_name_needed;
+
+ break;
+ }
+
+ if (c - folder_sys >= NAME_LIMIT)
+ return quote_name_bad;
+ }
+
+ return ret;
+ }
+
+
+ /* This is written to temporary file */
+ static int dump_last_read_cache P_((FILE *f,
+ const char * filename /* temp file name */,
+ struct file_changes * cache_file,
+ struct sortlist * cache_entries,
+ int * errno_res,
+
+ /* May be NULL */
+ FILE *commentfile,
+ const char *actor,
+ char *version_buff
+ ));
+ static int dump_last_read_cache(f,filename,cache_file,cache_entries,errno_res,
+ commentfile,actor,version_buff)
+ FILE *f;
+ const char * filename /* temp file name */;
+ struct file_changes * cache_file;
+ struct sortlist * cache_entries;
+ int * errno_res;
+
+ /* May be NULL */
+ FILE * commentfile;
+ const char * actor;
+ char * version_buff;
+ {
+ int ret = 0;
+ size_t cache_len = 0;
+ int r;
+ size_t z1;
+
+ static char actor1[SLEN] = "";
+ static char version1[SLEN] = "";
+
+ if (actor && version_buff) {
+ strfcpy(actor1,actor,sizeof actor1);
+ strfcpy(version1,version_buff,sizeof version1);
+ } else if (actor1[0]) { /* Sticky */
+ actor = &(actor1[0]);
+ version_buff = &(version1[0]);
+ }
+
+ if (! cache_entries) {
+ ret = 0;
+
+ goto fail;
+ }
+
+ cache_len = sort_list_len(cache_entries);
+
+ if ((z1=fwrite(LAST_READ_HEADER,1, LAST_READ_HEADER_len,f)) <
+ LAST_READ_HEADER_len) {
+
+ if (ferror(f)) {
+ int err = errno;
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: fwrite failed: %s\n",
+ filename,strerror(err)));
+
+ lib_error(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWriteTempFail,
+ "Write failed for last-read temp file %s: %s"),
+ filename,strerror(err));
+
+ if (errno_res)
+ *errno_res = err;
+ } else {
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: short fwrite = %zu < %zu\n",
+ filename,z1,LAST_READ_HEADER_len));
+ }
+
+ ret = 0;
+
+ goto fail;
+ }
+
+ /* commentfile,actor,version_buff may be NULL */
+ insert_commentfile(f,ELMLASTREAD_INFO,commentfile,
+ actor,version_buff);
+
+ if (cache_len > 0) {
+ size_t i;
+
+ size_t need_delete = 0;
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: cache_len=%zu\n",
+ filename,cache_len));
+
+ for (i = 0; i < cache_len; i++) {
+
+ union sort_item res;
+
+ res.last_read_entry = NULL;
+
+ /* Increments refcount */
+ get_sort_list_item(cache_entries,sort_list_get_normal,i,
+ &res);
+
+ if (res.last_read_entry) {
+ struct last_read_entry * entry;
+ enum quote_name_res q;
+ char * X;
+
+ if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,
+ "dump_last_read_cache",
+ "Bad magic type (last_read_entry)",0);
+
+ entry = res.last_read_entry;
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: entry %zu = %Q",
+ i,entry->folder_sys));
+
+ DPRINT(Debug,14,(&Debug,", entry_flags=%u %s",
+ entry->entry_flags,
+ give_entry_flags(entry->entry_flags)
+ ));
+
+ if (ison(entry->entry_flags,
+ LAST_READ_delete)) {
+ need_delete++;
+
+ DPRINT(Debug,14,(&Debug," -- delete, skipping\n"));
+ goto skip_this_entry;
+ }
+
+ if (isoff(entry->entry_flags,
+ LAST_READ_valid)) {
+ DPRINT(Debug,14,(&Debug," -- not valid, skipping\n"));
+ goto skip_this_entry;
+ }
+
+ if (ison(entry->entry_flags,
+ LAST_READ_memonly)) {
+ DPRINT(Debug,14,(&Debug," -- mem only, skipping\n"));
+ goto skip_this_entry;
+ }
+
+ q = quote_name(entry->folder_sys);
+ DPRINT(Debug,14,(&Debug," quote name = %d",
+ q));
+ switch (q) {
+ case quote_name_bad:
+ DPRINT(Debug,14,(&Debug," quote_name_bad")); break;
+ case quote_name_no:
+ DPRINT(Debug,14,(&Debug," quote_name_no")); break;
+ case quote_name_needed:
+ DPRINT(Debug,14,(&Debug," quote_name_needed")); break;
+ }
+
+ if (q <= quote_name_bad) {
+ DPRINT(Debug,14,(&Debug,", skipping\n"));
+ setit(entry->entry_flags,LAST_READ_memonly);
+ goto skip_this_entry;
+ } else if (q > quote_name_no) {
+ DPRINT(Debug,14,(&Debug,", quoting\n"));
+
+ elm_fprintf(f,FRM("%Q"),entry->folder_sys);
+ } else {
+ DPRINT(Debug,14,(&Debug,"\n"));
+
+ fputs(entry->folder_sys,f);
+ }
+
+ /* Both space and TAB allowed */
+ putc('\t',f);
+
+ if (ison(entry->entry_flags,
+ LAST_READ_have_st_ino)) {
+
+ fprintf(f,"%lu",(unsigned long)(entry->st_ino));
+
+ } else
+ putc('-',f); /* Placeholder */
+
+ /* Both space and TAB allowed */
+ putc('\t',f);
+
+ fprintf(f,"%ld",(long)(entry->last_read));
+
+ X = ctime(&(entry->last_read));
+
+ /* ctime() includes newline \n to result */
+ if (X) {
+ fprintf(f,"\t# %s",
+ X);
+
+ } else
+ putc('\n',f);
+
+ skip_this_entry:
+ free_last_read_entry(& res.last_read_entry);
+
+ }
+ }
+
+
+ if (ferror(f)) {
+ int err = errno;
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: write failed: %s\n",
+ filename,strerror(err)));
+
+ lib_error(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWriteTempFail,
+ "Write failed for last-read temp file %s: %s"),
+ filename,strerror(err));
+
+ if (errno_res)
+ *errno_res = err;
+
+ ret = 0;
+ goto fail;
+ }
+
+ r = fflush(f);
+ switch(r) {
+ int err;
+ case 0:
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: written\n",
+ filename));
+ ret = 1;
+ break;
+ case EOF:
+ err = errno;
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: flush failed: %s\n",
+ filename,strerror(err)));
+
+ lib_error(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWriteTempFail,
+ "Write failed for last-read temp file %s: %s"),
+ filename,strerror(err));
+
+ if (errno_res)
+ *errno_res = err;
+
+ ret = 0;
+ goto fail;
+ }
+
+ if (cache_file) {
+ if (! stat_last_read_cache(filename,f,cache_file)) {
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: stat %s failed\n",
+ filename));
+ ret = 0;
+ goto fail;
+ }
+ }
+
+ if (need_delete > 0) {
+
+ size_t i = cache_len -1;
+ size_t deleted = 0;
+ size_t valid = 0;
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: %zu entries marked for delete\n",
+ filename,need_delete));
+
+ while (1) {
+ union sort_item res;
+
+ res.last_read_entry = NULL;
+
+ /* Increments refcount */
+ get_sort_list_item(cache_entries,sort_list_get_normal,i,
+ &res);
+
+ if (res.last_read_entry) {
+ struct last_read_entry * entry;
+
+ if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,
+ "dump_last_read_cache",
+ "Bad magic type (last_read_entry)",0);
+
+ entry = res.last_read_entry;
+
+ if (ison(entry->entry_flags,LAST_READ_valid))
+ valid++;
+
+ if (ison(entry->entry_flags,LAST_READ_delete)) {
+
+ free_last_read_entry(& res.last_read_entry);
+
+ /* Increments refcount */
+ get_sort_list_item(cache_entries,sort_list_get_remove,i,
+ &res);
+
+ if (res.last_read_entry) {
+ struct last_read_entry * entry;
+
+ if (LAST_READ_ENTRY_magic != res.last_read_entry->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,
+ "dump_last_read_cache",
+ "Bad magic type (last_read_entry)",0);
+
+ entry = res.last_read_entry;
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: #%zu folder_sys=%s - deleted\n",
+ i,entry->folder_sys));
+
+
+ deleted++;
+ }
+ }
+
+ if (res.last_read_entry)
+ free_last_read_entry(& res.last_read_entry);
+ }
+
+ if (i > 0)
+ i--;
+ else
+ break;
+ }
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: %zu valid, %zu deleted.\n",
+ filename,valid,deleted));
+ }
+
+ } else {
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache: %s: No entries\n",
+ filename
+ ));
+ }
+
+
+
+ fail:
+
+ DPRINT(Debug,14,(&Debug,
+ "dump_last_read_cache=%d%s; filename=%s\n",
+ ret,
+ ret ? " (succeed)" : "",
+ filename));
+ return ret;
+ }
+
+
+
+ static struct last_read_cache *malloc_last_read_cache(sys_dir,st,
+ prealloc,fchanges,
+ filename)
+ const char * sys_dir;
+ const struct stat * st;
+ size_t prealloc;
+ const struct file_changes * fchanges;
+ const char * filename;
+ {
+ struct last_read_cache * ret =
+ safe_zero_alloc(sizeof (*ret));
+
+ ret -> magic = LAST_READ_CACHE_magic;
+
+ ret -> refcount = 1;
+
+ ret -> sys_dir = sys_dir ? safe_strdup(sys_dir) : NULL;
+ ret -> cached_name = NULL;
+
+
+ if (filename) {
+ ret -> cache_file_name = safe_strdup(filename);
+ } else
+ ret -> cache_file_name = NULL; /* Filled later */
+
+ ret->cache_file = NULL_file_changes;
+
+ if (fchanges)
+ ret->cache_file = *fchanges;
+
+ if (st)
+ stat_to_file_changes(st,& (ret->cache_file));
+
+ ret->entries = alloc_sort_list(&last_read_entry_op,
+ prealloc);
+
+ ret->modified = 0;
+ ret->read = 0;
+
+ return ret;
+ }
+
+ enum last_read_mode {
+ last_read_read_only = 0,
+ last_read_check,
+ last_read_read_update /* opended for rewrite */,
+ last_read_create /* Create for locking */
+ };
+
+
+ enum LREAD_OPEN_bits {
+ LREAD_OPEN_bit_SUGGEST_REWRITE,
+ LREAD_OPEN_bit_FILE_FD_LOCKED,
+ LREAD_OPEN_bit_WRITTEN,
+
+ LREAD_OPEN_bit_count
+ };
+
+ #define LREAD_OPEN_SUGGEST_REWRITE (1 << LREAD_OPEN_bit_SUGGEST_REWRITE)
+ #define LREAD_OPEN_FILE_FD_LOCKED (1 << LREAD_OPEN_bit_FILE_FD_LOCKED)
+ #define LREAD_OPEN_WRITTEN (1 << LREAD_OPEN_bit_WRITTEN)
+
+
+ #define LAST_READ_OPEN_magic 0xFA0E
+
+ static struct last_read_open {
+ unsigned short magic; /* LAST_READ_OPEN_magic */
+
+ int file_fd;
+ FILE * fh;
+
+ const char * filename;
+ struct dt_flags_info * locking_flags;
+
+ enum last_read_mode is_update;
+
+ unsigned int lread_open_flags : LREAD_OPEN_bit_count;
+
+ } * open_last_read_cache P_((const char * filename,
+ struct dt_flags_info * locking_flags,
+ enum last_read_mode is_update,
+ struct file_changes * file_information,
+ int * errno_res
+ ));
+
+ static struct last_read_open * open_last_read_cache(filename,
+ locking_flags,
+ is_update,
+ file_information,
+ errno_res)
+ const char * filename;
+ struct dt_flags_info * locking_flags;
+ enum last_read_mode is_update;
+ struct file_changes * file_information;
+ int * errno_res;
+ {
+ struct last_read_open * ret = NULL;
+
+ enum FLOCKING_mode fm = FLOCKING_exclusive;
+ char * openm = "r+";
+ int accm = O_RDWR;
+ mode_t creatm = 0600; /* Supposed to be read only
+ by user */
+
+ int file_fd = -1;
+ int file_fd_locked = 0;
+ int loop_count = 0;
+ int loop_message_printed = 0;
+
+ FILE * f = NULL;
+
+ struct stat file_fd_stat;
+ struct stat filename_stat;
+
+ int have_file_fd_stat = 0;
+ int have_filename_stat = 0;
+ int have_creat_retry = 0;
+
+
+ DPRINT(Debug,10,(&Debug,
+ "open_last_read_cache: is_update=%d",
+ is_update));
+
+ switch (is_update) {
+ case last_read_read_only:
+ DPRINT(Debug,10,(&Debug," last_read_read_only"));
+ fm = FLOCKING_shared;
+ openm = "r";
+ accm = O_RDONLY;
+
+ break;
+
+ case last_read_check:
+ DPRINT(Debug,10,(&Debug," last_read_check"));
+
+ if (0) {
+ case last_read_read_update:
+ DPRINT(Debug,10,(&Debug," last_read_read_update"));
+ }
+ fm = FLOCKING_exclusive;
+ openm = "r+";
+ accm = O_RDWR;
+ break;
+
+ case last_read_create:
+ DPRINT(Debug,10,(&Debug," last_read_create"));
+ fm = FLOCKING_exclusive;
+ openm = "r+";
+ accm = O_RDWR;
+ break;
+ }
+ DPRINT(Debug,10,(&Debug," filename=%Q\n",
+ filename));
+
+ while (-1 == file_fd) {
+ enum syscall_status r;
+ enum FLOCKING_status r1;
+
+ int err = can_open(filename,openm);
+ int creatf = 0;
+
+ file_fd_locked = 0;
+
+ if (err) {
+ DPRINT(Debug,2,(&Debug,
+ "open_last_read_cache: %s: %s (can_open)\n",
+ filename,strerror(err)));
+
+ if (EINTR == err) {
+ continue;
+ }
+
+ if (ENOENT == err &&
+ last_read_create == is_update &&
+ ! have_creat_retry) {
+
+ DPRINT(Debug,10,(&Debug,
+ "open_last_read_cache: %s: Trying create file\n",
+ filename));
+
+ creatf = O_CREAT|O_EXCL;
+ } else {
+ if (loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWaitingFail,
+ "Waiting last-read file %s to be updated... Fail: %s"),
+ filename,strerror(err));
+ }
+
+ if (errno_res)
+ *errno_res = err;
+
+ return NULL;
+ }
+
+ } else {
+ have_creat_retry = 0;
+ }
+
+ file_fd = open(filename,accm|creatf,creatm);
+
+ if (-1 == file_fd) {
+ err = errno;
+
+ DPRINT(Debug,10,(&Debug,"open_last_read_cache: %s: %s\n",
+ filename,strerror(err)));
+
+ if (EINTR == err) {
+ continue;
+ }
+
+ if (EEXIST == err) {
+ /* Must have create failure
+ -- retry with canopen()
+ */
+
+ DPRINT(Debug,10,(&Debug,
+ "open_last_read_cache: %s: Trying open file\n",
+ filename));
+
+ have_creat_retry = 1;
+ continue;
+ }
+
+ if (loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWaitingFail,
+ "Waiting last-read file %s to be updated... Fail: %s"),
+ filename,strerror(err));
+ }
+
+ if (errno_res)
+ *errno_res = err;
+
+ return NULL;
+ }
+
+ r = fstat(file_fd,&file_fd_stat);
+ switch (r) {
+ char *X;
+ case syscall_success:
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: fstat %d: %s succeed: dev %lu ino %lu size %ld modified %ld",
+ file_fd,filename,
+ (unsigned long)file_fd_stat.st_dev,
+ (unsigned long)file_fd_stat.st_ino,
+ (long)file_fd_stat.st_size,
+ (long)file_fd_stat.st_mtime));
+
+ X = ctime(& (file_fd_stat.st_mtime));
+ if (X) { /* ctime() includes newline */
+ DPRINT(Debug,14,(&Debug," -- %s",X));
+ } else {
+ DPRINT(Debug,14,(&Debug,"\n"));
+ }
+
+ have_file_fd_stat = 1;
+
+ break;
+ case syscall_error:
+ err = errno;
+
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: fstat %d: %s failed: %s\n", + file_fd,filename,strerror(err)));
+
+ if (EINTR == err) {
+ goto oops;
+ }
+
+ /* Just read old file ? */
+ goto quit_locking_loop;
+ }
+
+ /* <last_read> is locked with exclusive lock
+ when new file <last_read>.N is written
+ and then renamed to <last_read>
+
+ */
+
+ r1 = filelock_fd(file_fd,fm,
+ locking_flags,
+ filename,
+ FLOCKING_non_block,
+ &err);
+
+ switch (r1) {
+ case FLOCKING_FAIL:
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: filelock_fd %d: %s locking failed: %s\n",
+ file_fd,filename,strerror(err)));
+
+ if (errno_res)
+ *errno_res = err;
+
+ /* Just read old file ? */
+ goto quit_locking_loop;
+ case FLOCKING_OK:
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: filelock_fd %d: %s locked\n",
+ file_fd,filename));
+ file_fd_locked = 1;
+ break;
+ case FLOCKING_RETRY:
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: filelock_fd %d: %s locking failed (retry)",
+ file_fd,filename));
+ if (err) {
+ DPRINT(Debug,14,(&Debug,": %s",
+ strerror(err)));
+ }
+ DPRINT(Debug,14,(&Debug,"\n"));
+
+ if (EINTR == err) {
+ goto oops;
+ }
+
+ goto wait_to_change;
+ case FLOCKING_UNSUPPORTED:
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: filelock_fd %d: %s locking not supported\n",
+ file_fd,filename));
+ /* Just read old file ? */
+ goto quit_locking_loop;
+ }
+
+ r = stat(filename,&filename_stat);
+ switch (r) {
+ char *X;
+ case syscall_success:
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: stat %s succeed: dev %lu ino %lu size %ld modified %ld",
+ filename,
+ (unsigned long)filename_stat.st_dev,
+ (unsigned long)filename_stat.st_ino,
+ (long)filename_stat.st_size,
+ (long)filename_stat.st_mtime));
+ X = ctime(& (filename_stat.st_mtime));
+ if (X) { /* ctime() includes newline */
+ DPRINT(Debug,14,(&Debug," -- %s",X));
+ } else {
+ DPRINT(Debug,14,(&Debug,"\n"));
+ }
+
+ have_filename_stat = 1;
+
+ break;
+ case syscall_error:
+ err = errno;
+
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: stat %s: %s\n",
+ filename,strerror(err)));
+ if (EINTR == err) {
+ goto oops;
+ }
+
+ /* Just read old file ? */
+ goto quit_locking_loop;
+ }
+
+ if (!have_filename_stat || !have_file_fd_stat) {
+
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: file %s - no stat?\n",
+ filename));
+
+ goto quit_locking_loop;
+
+ } else if (filename_stat.st_dev == file_fd_stat.st_dev &&
+ filename_stat.st_ino == file_fd_stat.st_ino &&
+ filename_stat.st_size == file_fd_stat.st_size &&
+ filename_stat.st_mtime == file_fd_stat.st_mtime) {
+
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: file %s not changed (since open)\n",
+ filename));
+
+ if (loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWaitingOK,
+ "Waiting last-read file %s to be updated... OK"),
+ filename);
+ loop_message_printed = 0;
+ }
+
+ goto quit_locking_loop;
+
+ } else {
+ int wait_it;
+
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: file %s changed after open\n",
+ filename));
+
+ oops:
+ wait_it = 0;
+
+ if (0) {
+ wait_to_change:
+ wait_it = 1;
+ }
+
+ if (loop_count++ > 10) {
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: file %s - try #%d -- quiting\n",
+ filename,loop_count));
+ goto quit_locking_loop;
+ }
+
+ if (wait_it) {
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: file %s - try #%d -- waiting\n",
+ filename,loop_count));
+
+ if (!loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWaiting,
+ "Waiting last-read file %s to be updated..."),
+ filename);
+ loop_message_printed = 1;
+ }
+
+ if (POLL_method)
+ wait_for_timeout(5);
+ else
+ sleep(5);
+
+ } else {
+ DPRINT(Debug,14,(&Debug,
+ "open_last_read_cache: file %s - try #%d -- looping\n",
+ filename,loop_count));
+ }
+
+ if (file_fd_locked) { /* Just ignore error --
+ close() should release this anyway
+ */
+ filelock_fd(file_fd,FLOCKING_release,locking_flags,
+ filename,FLOCKING_non_block,NULL);
+ }
+
+ close(file_fd); /* Result ignored */
+ file_fd = -1;
+ }
+ }
+
+ quit_locking_loop:
+
+ if (loop_message_printed) {
+ lib_transient(CATGETS(elm_msg_cat, MeSet,
+ MeLastReadWaitingError,
+ "Waiting last-read file %s to be updated... Error"),
+ filename);
+ }
+
+ if (file_information) {
+ if (FILE_CHANGES_magic != file_information->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,"open_last_read_cache",
+ "Bad magic number (file_changes)",0);
+
+ if (sizeof (*file_information) != file_information->self_size) {
+
+ DPRINT(Debug,1,(&Debug,
+ "open_last_read_cache: size mismatch file_changes size %zu != self size %zu\n",
+ sizeof (*file_information),file_information->self_size));
+
+ } else {
+ stat_to_file_changes(have_file_fd_stat ? &file_fd_stat : NULL,
+ file_information);
+ }
+ }
+
+ f = fdopen(file_fd,openm);
+ if (!f) {
+ int err = errno;
+ DPRINT(Debug,10,(&Debug,
+ "open_last_read_cache: fdopen %d: %s: %s\n",
+ file_fd,filename,strerror(err)));
+
+ if (file_fd_locked) { /* Just ignore error --
+ close() should release this anyway
+ */
+ filelock_fd(file_fd,FLOCKING_release,locking_flags,
+ filename,FLOCKING_non_block,NULL);
+ }
+
+ close(file_fd); /* Result ignored */
+
+ if (errno_res)
+ *errno_res = err;
+
+ return NULL;
+ }
+
+
+ ret = safe_zero_alloc(sizeof (*ret));
+
+ ret->magic = LAST_READ_OPEN_magic;
+ ret->file_fd = file_fd;
+ ret->fh = f;
+ ret->filename = filename; /* shared */
+ ret->locking_flags = locking_flags;
+ ret->is_update = is_update;
+
+ #define IFSET(var,flag) (var ? flag : 0)
+
+ ret->lread_open_flags =
+ IFSET(file_fd_locked,LREAD_OPEN_FILE_FD_LOCKED);
+
+ DPRINT(Debug,10,(&Debug,
+ "open_last_read_cache: %s open%s\n",
+ filename,
+ file_fd_locked ? ", file_fd locked" : ""));
+
+ return ret;
+ }
+
+ static void close_last_read_open P_((struct last_read_open *ptr));
+
+ /* Closes ptr->fh if not update */
+ static int read_last_read_cache P_((struct last_read_open *ptr,
+ struct file_changes * cache_file,
+ struct sortlist ** cache_entries,
+ int * errors,
+ const struct last_read_entry_def * entry_default));
+ static int read_last_read_cache(ptr,cache_file,cache_entries,errors,entry_default)
+ struct last_read_open *ptr;
+ struct file_changes * cache_file;
+ struct sortlist ** cache_entries;
+ int * errors;
+ const struct last_read_entry_def * entry_default;
+ {
+ int ret = 0;
+ int suggest_rewrite = 0;
+
+
+ if (LAST_READ_OPEN_magic != ptr->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,
+ "read_last_read_cache",
+ "Bad magic number (last_read_open)",0);
+
+ if (! ptr->fh) {
+ ret = 0;
+ goto fail;
+ }
+
+ rewind(ptr->fh);
+
+ ret = parse_last_read_cache(ptr->filename,
+ ptr->fh,
+ cache_file,
+ cache_entries,
+ errors,
+ entry_default,
+ &suggest_rewrite);
+
+ if (ptr -> is_update < last_read_check ||
+ (last_read_check == ptr -> is_update &&
+ ! suggest_rewrite)) {
+ close_last_read_open(ptr);
+ }
+
+ if (suggest_rewrite)
+ setit(ptr->lread_open_flags,
+ LREAD_OPEN_SUGGEST_REWRITE);
+
+ fail:
+
+ DPRINT(Debug,14,(&Debug,
+ "read_last_read_cache=%d; filename=%s\n",
+ ret,ptr->filename));
+
+
+ return ret;
+
+ }
+
+ static void close_last_read_open(ptr)
+ struct last_read_open *ptr;
+ {
+ if ( LAST_READ_OPEN_magic != ptr->magic)
+ panic("MBX PANIC",__FILE__,__LINE__,
+ "close_last_read_entry",
[continued in next message]
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)