• Patch: Elm ME+ 2.5 PLalpha63 -> Elm ME+ 2.5 PLalpha64 [2/4] (4/5)

    From Kari Hurtta@21:1/5 to All on Tue Jul 2 20:52:17 2024
    [continued from previous message]

    + last_read_def_rewrite = ison(H->lread_open_flags,
    + LREAD_OPEN_SUGGEST_REWRITE);
    + }
    +
    +
    + if (write_last_read_cache(H,
    + dir_last_read,
    + locking,
    + NULL /* errno_res */,
    +
    + /* commentfile,actor,version_buff */ + NULL,NULL,NULL
    + )) {
    +
    + DPRINT(Debug,14,(&Debug,
    + "write_last_read_cache: %s: %s updated\n",
    + dir_last_read->sys_dir ?
    + dir_last_read->sys_dir : "fallback file", + dir_last_read->cache_file_name));
    +
    + if (last_read_def_cache == dir_last_read) {
    + last_read_def_rewrite = 0;
    + }
    +
    + }
    +
    + free_last_read_open(&H);
    + }
    + }
    + }
    +
    + }
    +
    + enum last_read_default { last_read_def_existing = 0,
    + last_read_def_create };
    +
    + static struct last_read_cache * give_last_read P_((const char * sys_dir,
    + enum last_read_location last_read_loc,
    + const char * res_dir,
    + enum last_read_default default_create
    + ));
    +
    + static struct last_read_cache * give_last_read(sys_dir,last_read_loc,res_dir,
    + default_create)
    + const char * sys_dir;
    + enum last_read_location last_read_loc;
    + const char * res_dir;
    + enum last_read_default default_create;
    + {
    + struct last_read_cache * ret = NULL;
    + char * fname = NULL;
    +
    + DPRINT(Debug,13,(&Debug,"give_last_read: sys_dir=%s last_read_loc=%d",sys_dir,last_read_loc));
    + switch (last_read_loc) {
    + case read_loc_none: DPRINT(Debug,13,(&Debug," read_loc_none")); break;
    + case read_loc_dir: DPRINT(Debug,13,(&Debug," read_loc_dir")); break;
    + case read_loc_def: DPRINT(Debug,13,(&Debug," read_loc_def")); break;
    + }
    + if (res_dir) {
    + DPRINT(Debug,13,(&Debug," res_dir=%s",res_dir));
    + }
    + DPRINT(Debug,13,(&Debug," default_create=%d",default_create));
    + switch (default_create) {
    + case last_read_def_existing: DPRINT(Debug,13,(&Debug," last_read_def_existing")); break;
    + case last_read_def_create: DPRINT(Debug,13,(&Debug," last_read_def_create")); break;
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + fname = give_cache_file_name(sys_dir,last_read_loc);
    +
    + if (fname) {
    + enum sort_list_search_op op = sort_list_search_normal;
    + enum use_lastread_v use_lastread =
    + give_dt_enumerate_as_int(&use_last_read_file);
    +
    +
    + switch (use_lastread) {
    + case use_lastread_no:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s - use-last-read disabled\n",
    + sys_dir));
    + goto fail;
    +
    + case use_lastread_yes:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s - use-last-read enabled\n",
    + sys_dir));
    + op = sort_list_search_create;
    + break;
    + case use_lastread_auto:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s - use-last-read auto\n",
    + sys_dir));
    +
    + if (0) {
    + case use_lastread_existing:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s - use-last-read existing\n",
    + sys_dir));
    + }
    +
    + switch (default_create) {
    + case last_read_def_create:
    + op = sort_list_search_create;
    + break;
    + case last_read_def_existing: {
    + enum syscall_status r_access =
    + access(fname, ACCESS_EXISTS);
    +
    + switch ( r_access) {
    + int err UNUSED_VAROK;
    + case syscall_success:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s - %s exists\n",
    + sys_dir,fname));
    + op = sort_list_search_create;
    + break;
    + case syscall_error:
    + err = errno;
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s - %s gives: %s\n",
    + sys_dir,fname,
    + strerror(err)));
    + break;
    + }
    + }
    + break;
    + }
    +
    + break;
    + case NUM_use_lastread:
    + break;
    + }
    +
    + switch (last_read_loc) {
    +
    + case read_loc_none:
    + break;
    + case read_loc_dir:
    +
    + if (res_dir) {
    + struct last_read_cache_def def = NULL_last_read_cache_def;
    + union sort_item_default def0;
    + union sort_item res;
    + size_t idx;
    + union sort_key key;
    +
    + if (! last_read_dir_cache) {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- setting last_read_dir_cache\n",
    + sys_dir));
    +
    + last_read_dir_cache = alloc_sort_list(& last_read_cache_op,2);
    + }
    +
    + def.st = NULL;
    + def.prealloc = 5;
    + def.fchanges = NULL;
    +
    + def0.last_read_cache = &def;
    + def.cache_file_name = fname;
    +
    + res.last_read_cache = NULL;
    + key.str = res_dir;
    + idx = 0;
    +
    + /* Increments refcount */;
    + if (search_sort_list_item(last_read_dir_cache,
    + op,
    + key,def0,&res,&idx,NULL)) {
    +
    + if (res.last_read_cache) {
    + if (LAST_READ_CACHE_magic != res.last_read_cache->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"give_last_read",
    + "Bad magic type (last_read_cache)",0);
    +
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- last read %Q: idx #%zu found\n",
    + sys_dir,res_dir,idx));
    +
    + ret = res.last_read_cache;
    +
    + if (! ret->read) {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- need initial read\n",
    + sys_dir));
    +
    + reload_last_read_cache(ret,NULL,NULL,
    + cache_guess_locking(ret),
    + last_read_check,
    + NULL /* errno_res */);
    + } else {
    + int err = 0;
    + enum file_changes_result change_status
    + = test_file_changes(fname,
    + & ret->cache_file,
    + & err);
    +
    + switch (change_status) {
    + case no_file_changes:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s last_read %s not changed\n",
    + sys_dir,fname));
    + break;
    + case file_changes_error:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s last_read %s not available %s\n",
    + sys_dir,fname,strerror(err))); + break;
    + case have_file_changes:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s last_read %s need reload\n",
    + sys_dir,fname));
    +
    + reload_last_read_cache(ret,NULL,NULL,
    + cache_guess_locking(ret),
    + last_read_check,
    + NULL /* errno res */);
    + break;
    + }
    + }
    +
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- last read for %Q: search_sort_list_item did not set last_read_cache, idx #%zu\n",
    + sys_dir,res_dir,idx));
    + }
    +
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- last read for %Q not found or created\n",
    + sys_dir,res_dir));
    + }
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- target dir not set\n", + sys_dir));
    + }
    + break;
    + case read_loc_def: {
    + struct last_read_open * H = NULL;
    +
    + if (last_read_def_cache) {
    +
    + ret = last_read_def_cache;
    + inc_last_read_cache_refcount(ret);
    +
    + if (! ret->read) {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- need initial read for default cache %s\n",
    + sys_dir,fname));
    +
    + reload_last_read_cache(ret,&H,NULL,
    + &conf_merge_locking,
    + last_read_check,
    + NULL /* errno_res */);
    + } else {
    +
    + int err = 0;
    + enum file_changes_result change_status
    + = test_file_changes(fname,
    + & ret->cache_file,
    + & err);
    +
    + switch (change_status) {
    + case no_file_changes:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s last_read %s not changed\n",
    + sys_dir,fname));
    + break;
    + case file_changes_error:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s last_read %s not available %s\n",
    + sys_dir,fname,strerror(err)));
    + break;
    + case have_file_changes:
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s last_read %s need reload\n",
    + sys_dir,fname));
    +
    + reload_last_read_cache(ret,&H,NULL,
    + &conf_merge_locking,
    + last_read_check,
    + NULL /* errno_res */);
    + break;
    + }
    + }
    +
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- default cache %s not read\n",
    + sys_dir,fname));
    +
    + last_read_def_cache =
    + load_last_read_cache(user_last_read_def,NULL,
    + &H,NULL, &conf_merge_locking,
    + last_read_check);
    +
    + if (last_read_def_cache) {
    + ret = last_read_def_cache;
    + inc_last_read_cache_refcount(ret);
    +
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- succeed to read default cache %s\n",
    + sys_dir,fname));
    + } else {
    + switch (default_create) {
    + case last_read_def_create:
    + last_read_def_cache = malloc_last_read_cache(NULL /* sys_dir */,
    + NULL /* struct stat */,
    + 1,
    + &last_read_def_fchanges,
    + fname);
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s - created dummy default cache %s\n",
    + sys_dir,fname));
    +
    + ret = last_read_def_cache;
    + inc_last_read_cache_refcount(ret);
    +
    + break;
    + case last_read_def_existing:
    + break;
    + }
    + }
    + }
    +
    + if (H) {
    +
    + if (LAST_READ_OPEN_magic != H->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,
    + "write_last_read_cache",
    + "Bad magic number (last_read_open)",0);
    +
    + if (last_read_def_cache) {
    + last_read_def_rewrite = ison(H->lread_open_flags,
    + LREAD_OPEN_SUGGEST_REWRITE);
    + }
    +
    + free_last_read_open(&H);
    + }
    +
    + }
    + break;
    + }
    +
    + fail:
    + free(fname);
    + fname = NULL;
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read: %s -- cache file name not set\n",
    + sys_dir));
    + }
    +
    + if (ret) {
    + if (LAST_READ_CACHE_magic != ret->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"give_last_read",
    + "Bad magic type (last_read_cache)",0);
    +
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read=%p",ret));
    + if (ret->sys_dir) {
    + DPRINT(Debug,13,(&Debug," sys_dir=%s",ret->sys_dir));
    + }
    + if (ret->cache_file_name) {
    + DPRINT(Debug,13,(&Debug," cache_file_name=%s",ret->cache_file_name));
    + }
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "give_last_read=NULL"));
    + }
    +
    + DPRINT(Debug,13,(&Debug,"; requested sys_dir=%s",sys_dir));
    + if (res_dir) {
    + DPRINT(Debug,13,(&Debug," res_dir=%s",res_dir));
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + return ret;
    + }
    +
    + /* Result is malloced if *free_sys_dir is set */
    + static char * stat_file_to_sys_dir P_((const char * stat_file,
    + int * free_sys_dir_p
    + ));
    + static char * stat_file_to_sys_dir (stat_file,free_sys_dir_p)
    + const char * stat_file;
    + int * free_sys_dir_p;
    + {
    + char * sys_dir = NULL;
    + int free_sys_dir = * free_sys_dir_p;
    +
    + const char * p = strrchr(stat_file,'/');
    +
    + if (p) {
    + size_t len = (p - stat_file);
    +
    + sys_dir = safe_malloc(len+1);
    + free_sys_dir = 1;
    + strnfcpy(sys_dir,stat_file,len,len+1,NULL);
    +
    + } else {
    + sys_dir = ".";
    + free_sys_dir = 0;
    + }
    +
    +
    + DPRINT(Debug,14,(&Debug,
    + "stat_file_to_sys_dir=%s; stat_file=%s\n",
    + sys_dir,
    + stat_file));
    +
    + * free_sys_dir_p = free_sys_dir;
    + return sys_dir;
    + }
    +
    + /* Increments refcount - may change or open new cache
    + does not reload cache if directory is corrent
    + */
    + struct last_read_cache * upgrade_last_read(dir_last_read,
    + stat_file,
    + stat_buf)
    + struct last_read_cache * dir_last_read;
    + const char * stat_file;
    + struct stat * stat_buf;
    + {
    + struct last_read_cache *ret = NULL;
    + int need_upgrade = 0;
    +
    + int free_sys_dir = 0;
    + char * sys_dir = stat_file_to_sys_dir(stat_file,
    + &free_sys_dir);
    + const char * res_dir = NULL;
    +
    + enum last_read_location last_read_loc = read_loc_none;
    +
    +
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s => sys_dir=%Q\n",
    + stat_file,sys_dir));
    +
    + last_read_loc = last_read_dir_to_loc(sys_dir,&res_dir);
    +
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s => location %d",
    + stat_file,
    + last_read_loc));
    +
    + switch (last_read_loc) {
    + case read_loc_none: DPRINT(Debug,13,(&Debug," read_loc_none"));
    + break;
    + case read_loc_dir: DPRINT(Debug,13,(&Debug," read_loc_dir"));
    + break;
    + case read_loc_def: DPRINT(Debug,13,(&Debug," read_loc_def"));
    + break;
    + }
    +
    + if (res_dir) {
    + DPRINT(Debug,13,(&Debug," res_dir=%Q",res_dir));
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + if (dir_last_read) {
    +
    + if (LAST_READ_CACHE_magic != dir_last_read->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
    + "Bad magic type (last_read_cache)",0);
    +
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s dir_last_read=%p",
    + stat_file,dir_last_read));
    + if (dir_last_read->sys_dir) {
    + DPRINT(Debug,13,(&Debug," sys_dir=%s",dir_last_read->sys_dir));
    + }
    + if (dir_last_read->cache_file_name) {
    + DPRINT(Debug,13,(&Debug," cache_file_name=%s",
    + dir_last_read->cache_file_name));
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + switch (last_read_loc) {
    + case read_loc_none: need_upgrade = 1; break;
    + case read_loc_dir:
    + if (res_dir && dir_last_read->sys_dir &&
    + same_dir_str(res_dir,dir_last_read->sys_dir)) {
    +
    + if (FILE_CHANGES_magic != dir_last_read->cache_file.magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
    + "Bad magic type (file_changes)",0);
    +
    + if (stat_buf &&
    + dir_last_read->cache_file.dev != stat_buf->st_dev) {
    +
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s -- last_read dev %ld does not match %Q dev %ld\n",
    + stat_file,
    + (long)(dir_last_read->cache_file.dev),
    + res_dir,
    + (long)(stat_buf->st_dev)));
    + need_upgrade = 1;
    + }
    +
    + } else {
    + need_upgrade = 1;
    + if (res_dir && dir_last_read->sys_dir) {
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s -- last_read %Q does not match to %Q\n",
    + stat_file,dir_last_read->sys_dir,
    + res_dir));
    +
    + }
    + }
    + break;
    + case read_loc_def:
    + if (last_read_def_cache != dir_last_read)
    + need_upgrade = 1;
    + break;
    + }
    +
    + if (need_upgrade) {
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s -- last read %s need upgrade\n",
    + stat_file,
    + dir_last_read->cache_file_name));
    + }
    + }
    +
    +
    + if (need_upgrade || !dir_last_read) {
    +
    + ret = give_last_read(sys_dir,last_read_loc,res_dir,
    + dir_last_read ? last_read_def_create :
    + last_read_def_existing
    + );
    +
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s ",
    + stat_file));
    +
    + if (ret) {
    + DPRINT(Debug,13,(&Debug," last_read for %s changed or set",
    + sys_dir));
    + } else {
    + DPRINT(Debug,13,(&Debug," last_read for %s failed",
    + sys_dir));
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + } else {
    + if (FILE_CHANGES_magic != dir_last_read->cache_file.magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
    + "Bad magic type (file_changes)",0);
    +
    + ret = dir_last_read;
    + inc_last_read_cache_refcount(ret);
    +
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read: %s last_read %s not changed\n",
    + stat_file,dir_last_read->cache_file_name));
    +
    + }
    +
    + if (sys_dir) {
    + if (free_sys_dir)
    + free(sys_dir);
    + sys_dir = NULL;
    + }
    +
    + if (ret) {
    + if (LAST_READ_CACHE_magic != ret->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"upgrade_last_read",
    + "Bad magic type (last_read_cache)",0);
    +
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read=%p",ret));
    + if (ret->sys_dir) {
    + DPRINT(Debug,13,(&Debug," sys_dir=%s",ret->sys_dir));
    + }
    + if (ret->cache_file_name) {
    + DPRINT(Debug,13,(&Debug," cache_file_name=%s",ret->cache_file_name));
    + }
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "upgrade_last_read=NULL"));
    + }
    + DPRINT(Debug,13,(&Debug,"; stat_file=%s\n",stat_file));
    +
    + return ret;
    + }
    +
    + void inc_last_read_cache_refcount(cache)
    + struct last_read_cache * cache;
    + {
    + if (LAST_READ_CACHE_magic != cache->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"inc_last_read_cache_refcount",
    + "Bad magic type (last_read_cache)",0);
    +
    + cache->refcount++;
    + }
    +
    + /* Decremetns refcount */
    + void free_last_read_cache(cache)
    + struct last_read_cache ** cache;
    + {
    +
    + if (LAST_READ_CACHE_magic != (*cache)->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"free_last_read_cache",
    + "Bad magic type (last_read_cache)",0);
    +
    + if ((*cache)->refcount < 1)
    + panic("MBX PANIC",__FILE__,__LINE__,"free_last_read_cache",
    + "Bad refcount",0);
    +
    + (*cache)->refcount--;
    +
    + if ((*cache)->refcount > 0) {
    + (*cache) = NULL;
    +
    + return;
    + }
    +
    +
    + if ((*cache)->sys_dir) {
    + free((*cache)->sys_dir);
    +
    + (*cache)->sys_dir = NULL;
    + }
    +
    + if ((*cache)->cached_name)
    + free_string_sort(& ((*cache)->cached_name));
    +
    + if ((*cache)->cache_file_name) {
    + free((*cache)->cache_file_name);
    +
    + (*cache)->cache_file_name = NULL;
    + }
    +
    +
    + if ((*cache)->entries)
    + free_sort_list(& ((*cache)->entries));
    +
    + (*cache)->magic = 0; /* Invalidate */
    +
    + free(*cache);
    + *cache = NULL;
    + }
    +
    +
    + /* NULL if / without absolute path */
    + static const char * pathname_to_entryname P_((struct last_read_cache * this_last_read,
    + const char * pathname,
    + struct stat * file_stat));
    + static const char * pathname_to_entryname(this_last_read,pathname,file_stat) + struct last_read_cache * this_last_read;
    + const char * pathname;
    + struct stat * file_stat;
    + {
    + const char * name1 = pathname;
    +
    + if (LAST_READ_CACHE_magic != this_last_read->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"pathname_to_entryname",
    + "Bad magic type (last_read_cache)",0);
    +
    + if (this_last_read->sys_dir &&
    + in_directory(file_stat,pathname,this_last_read->sys_dir)) {
    +
    + char * x = strrchr(pathname,'/');
    +
    + DPRINT(Debug,13,(&Debug,
    + "pathname_to_entryname: %s on directory %s",
    + pathname,this_last_read->sys_dir));
    +
    + if (x && x[1]) {
    + name1 = x+1;
    +
    + DPRINT(Debug,13,(&Debug,", name => %s",
    + name1));
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    + }
    +
    + if (! name1[0]) {
    + DPRINT(Debug,13,(&Debug,
    + "pathname_to_entryname: %s - empty name\n",
    + pathname));
    + name1 = NULL;
    + } else if ('/' != name1[0] ) {
    +
    + const char * x1;
    +
    + for (x1 = name1; *x1; x1++) {
    + if ('/' == *x1) {
    + DPRINT(Debug,13,(&Debug,
    + "pathname_to_entryname: %s - invalid name %s\n",
    + pathname,name1));
    + name1 = NULL;
    + goto fail;
    + }
    + }
    + }
    +
    + fail:
    + return name1;
    + }
    +
    + /* Cache assumed to point correct directory */
    + int have_last_read(this_last_read,pathname,file_stat,last_read_time)
    + struct last_read_cache * this_last_read;
    + const char * pathname;
    + struct stat * file_stat;
    + time_t * last_read_time;
    + {
    + /* this_last_read is from upgrade_last_read() */
    +
    + const char * name1 = pathname;
    + int ret = 0;
    +
    + if (LAST_READ_CACHE_magic != this_last_read->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"have_last_read",
    + "Bad magic type (last_read_cache)",0);
    +
    + name1 = pathname_to_entryname(this_last_read,pathname,file_stat);
    +
    + if (!name1) {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: Invalid name\n",
    + pathname));
    + goto fail;
    + }
    +
    + if (this_last_read->entries) {
    + union sort_key key;
    + union sort_item res;
    + union sort_item_default def;
    + size_t idx = 0;
    +
    + key.str = name1;
    + def.last_read_entry = NULL;
    + res.dummy = NULL;
    +
    + if (search_sort_list_item(this_last_read->entries,
    + sort_list_search_normal,
    + key,def,&res,&idx,
    + NULL)) {
    +
    + if (res.last_read_entry) {
    + struct last_read_entry * entry = res.last_read_entry;
    +
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: %s found from %s idx %zu\n",
    + pathname,name1,
    + this_last_read->cache_file_name ?
    + this_last_read->cache_file_name : "(no name)", + idx));
    +
    + if (LAST_READ_ENTRY_magic != entry->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"have_last_read",
    + "Bad magic type (last_read_entry)",0);
    +
    + if (ison(entry->entry_flags,LAST_READ_valid)) {
    +
    + if (FILE_CHANGES_magic != this_last_read->cache_file.magic) + panic("MBX PANIC",__FILE__,__LINE__,"have_last_read",
    + "Bad magic number (file_changes)",0);
    +
    + if (file_stat && this_last_read->cache_file.valid) {
    +
    + if (this_last_read->cache_file.dev != file_stat->st_dev) {
    +
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: directory %s st_dev %ld != stat dev %ld\n",
    + pathname,
    + this_last_read->sys_dir ?
    + this_last_read->sys_dir :
    + "(default)",
    + (long) this_last_read->cache_file.dev,
    + (long) file_stat->st_dev));
    +
    + if (ison(entry->entry_flags, LAST_READ_have_st_ino)) {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: idx %zu %s have st_ino -- no match\n",
    + pathname,idx,
    + entry->folder_sys));
    + goto fail_match;
    + }
    +
    + } else {
    + if (isoff(entry->entry_flags, LAST_READ_have_st_ino)) {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: idx %zu %s have no st_ino -- no match\n",
    + pathname,idx,
    + entry->folder_sys));
    + goto fail_match;
    + }
    +
    + if (entry->st_ino != file_stat->st_ino) {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: idx %zu %s st_ino %lu != stat ino %lu -- no match\n",
    + pathname,idx,
    + (unsigned long) entry->st_ino, + (unsigned long) file_stat->st_ino,
    + entry->folder_sys));
    +
    + goto fail_match;
    + }
    + }
    + }
    +
    + if (entry->last_read > 0 &&
    + (time_t)-1 != entry->last_read) {
    + char *X = ctime(& (entry->last_read));
    +
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: entry %zu %s last_read %ld",
    + pathname,idx,
    + entry->folder_sys,
    + (long)entry->last_read));
    +
    + if (X) { /* ctime() includes newline */
    + DPRINT(Debug,13,(&Debug," -- %s",X));
    + } else {
    + DPRINT(Debug,13,(&Debug,"\n"));
    + }
    +
    + if (last_read_time)
    + *last_read_time = entry->last_read;
    +
    + ret = 1;
    + }
    +
    +
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: entry %zu %s not valid\n",
    + pathname,idx,
    + entry->folder_sys));
    + }
    +
    + fail_match:
    +
    + /* Decrements refcount */
    + free_last_read_entry(& res.last_read_entry);
    +
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: %s found from %s idx %zu - search_sort_list_item did not set last_read_entry\n",
    + pathname,name1,
    + this_last_read->cache_file_name ?
    + this_last_read->cache_file_name : "(no name)",
    + idx));
    + }
    +
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s: %s not found from %s\n",
    + pathname,name1,
    + this_last_read->cache_file_name ?
    + this_last_read->cache_file_name : "(no name)"));
    + }
    +
    + } else {
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read: %s no entries on %s\n",
    + pathname,
    + this_last_read->cache_file_name ?
    + this_last_read->cache_file_name : "(no name)"));
    + }
    +
    +
    + fail:
    + DPRINT(Debug,13,(&Debug,
    + "have_last_read=%d; pathname=%s",
    + ret,pathname));
    +
    + if (last_read_time && *last_read_time > 0 && (time_t)-1 != *last_read_time) {
    + char *X = ctime(last_read_time);
    + DPRINT(Debug,13,(&Debug,
    + " *last_read_time=%ld",
    + *last_read_time));
    +
    + if (X) { /* ctime() includes newline */
    + DPRINT(Debug,13,(&Debug," -- %s",X));
    + } else {
    + DPRINT(Debug,13,(&Debug,"\n"));
    + }
    + }
    +
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + return ret;
    + }
    +
    + /* Possible allocates new, decrement old refcount if name is changed */
    + int update_last_read(dir_last_read,sys_dir)
    + struct last_read_cache ** dir_last_read;
    + const char * sys_dir;
    + {
    + int cache_changed = 0;
    + int ret = 0;
    +
    + const char * resolved_dir = NULL;
    +
    + enum last_read_location new_loc = last_read_dir_to_loc(sys_dir,
    + &resolved_dir);
    +
    + if (*dir_last_read) {
    + if (LAST_READ_CACHE_magic != (*dir_last_read)->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"update_last_read",
    + "Bad magic type (last_read_cache)",0);
    +
    + DPRINT(Debug,13,(&Debug,
    + "update_last_read: old cache %p",
    + *dir_last_read));
    +
    + if ((*dir_last_read)->sys_dir) {
    + DPRINT(Debug,13,(&Debug,"; sys_dir=%s",
    + (*dir_last_read)->sys_dir));
    + }
    + if (last_read_def_cache == *dir_last_read) {
    + DPRINT(Debug,13,(&Debug,"; default cache"));
    + }
    + if ((*dir_last_read)->cache_file_name) {
    + DPRINT(Debug,13,(&Debug,"; cache_file_name=%s",
    + (*dir_last_read)->cache_file_name));
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + switch (new_loc) {
    + case read_loc_none: cache_changed = 1; break;
    + case read_loc_dir:
    + if (! (*dir_last_read)->sys_dir ||
    + ! resolved_dir ||
    + ! same_dir_str((*dir_last_read)->sys_dir,
    + resolved_dir))
    + cache_changed = 1;
    + break;
    + case read_loc_def:
    + if ((*dir_last_read)->sys_dir)
    + cache_changed = 1;
    +
    + }
    +
    + if (cache_changed)
    + free_last_read_cache(dir_last_read);
    +
    + } else
    + cache_changed = 1;
    +
    + if (cache_changed) {
    +
    + if (*dir_last_read)
    + panic("MBX PANIC",__FILE__,__LINE__,"update_last_read",
    + "Cache still set",0);
    +
    + if (read_loc_dir == new_loc) {
    + enum syscall_status r;
    +
    + r = access(sys_dir,WRITE_ACCESS|EXECUTE_ACCESS);
    +
    + switch (r) {
    + int err UNUSED_VAROK;
    + case syscall_error /* -1 */:
    + err = errno;
    +
    + DPRINT(Debug,10,(&Debug,
    + "update_last_read: No write access (and search) for %s: %s (errno=%d)\n",
    + sys_dir,strerror(err), err));
    +
    + /* No last_read_cache, if directory
    + is not writable and executable (searchable)
    + */
    + ret = 0;
    + goto out;
    + case syscall_success /* 0 */:
    + DPRINT(Debug,10,(&Debug,
    + "update_last_read: %s is accessible\n",
    + sys_dir));
    + break;
    + }
    + }
    +
    + /* locate from last_read_dir_cache */
    + /* or last_read_def_cache */
    +
    + (*dir_last_read) = give_last_read(sys_dir,
    + new_loc,resolved_dir,
    + last_read_def_existing);
    + }
    +
    + if (*dir_last_read) {
    + if (LAST_READ_CACHE_magic != (*dir_last_read)->magic)
    + panic("MBX PANIC",__FILE__,__LINE__,"update_last_read",
    + "Bad magic type (last_read_cache)",0);
    +
    + DPRINT(Debug,10,(&Debug,
    + "update_last_read: %s: cache %p",
    + sys_dir,*dir_last_read));
    +
    + if ((*dir_last_read)->sys_dir) {
    + DPRINT(Debug,10,(&Debug,"; sys_dir=%s",
    + (*dir_last_read)->sys_dir));
    + }
    + if (last_read_def_cache == *dir_last_read) {
    + DPRINT(Debug,10,(&Debug,"; default cache"));
    + }
    + if ((*dir_last_read)->cache_file_name) {
    + DPRINT(Debug,10,(&Debug,"; cache_file_name=%s",
    + (*dir_last_read)->cache_file_name));
    + }
    +
    + ret = 1;
    + } else {
    + DPRINT(Debug,10,(&Debug,
    + "update_last_read: %s: No cache",
    + sys_dir));
    +
    + ret = 0;
    + }
    +
    + if (cache_changed) {
    + DPRINT(Debug,10,(&Debug,"; cache changed\n"));
    + }
    + DPRINT(Debug,10,(&Debug,"\n"));
    +
    + out:
    + DPRINT(Debug,12,(&Debug,
    + "update_last_read=%d%s\n",
    + ret,
    + ret ? " last_read active" : ""));
    +
    + return ret;
    + }
    +
    +
    + /* Increments refcount */
    +
    +
    + struct last_read_cache * last_read_enabled(use_lastread,cur_folder_sys,
    + oldstat,curstat)
    + enum use_lastread_v use_lastread;
    + char * cur_folder_sys;
    + struct stat * oldstat;
    + struct stat * curstat;
    + {
    + struct last_read_cache *ret = NULL;
    +
    + int free_sys_dir = 0;
    + char * sys_dir = stat_file_to_sys_dir(cur_folder_sys,
    + &free_sys_dir);
    + enum last_read_location last_read_loc = read_loc_none;
    + const char * res_dir = NULL;
    +
    + enum last_read_default may_create = last_read_def_existing;
    + struct last_read_cache * last_read = NULL;
    +
    + DPRINT(Debug,13,(&Debug,
    + "last_read_enabled: use_lastread=%d",
    + use_lastread));
    +
    + switch (use_lastread) {
    + case use_lastread_no: DPRINT(Debug,13,(&Debug," use_lastread_no\n")); goto fail;
    + case use_lastread_yes: DPRINT(Debug,13,(&Debug," use_lastread_yes"));
    + may_create = last_read_def_create;
    + break;
    + case use_lastread_auto: DPRINT(Debug,13,(&Debug," use_lastread_auto")); break;
    + case use_lastread_existing: DPRINT(Debug,13,(&Debug," use_lastread_existing")); break;
    + case NUM_use_lastread: break;
    + }
    +
    + DPRINT(Debug,13,(&Debug,", cur_folder_sys=%s", cur_folder_sys));
    +
    + if (oldstat) {
    + DPRINT(Debug,13,(&Debug,
    + ", oldstat dev/ino=%lu/%lu atime=%ld",
    + (unsigned long)(oldstat->st_dev),
    + (unsigned long)(oldstat->st_ino),
    + (long)oldstat->st_atime));
    + }
    + if (curstat) {
    + DPRINT(Debug,13,(&Debug,
    + ", curstat dev/ino=%lu/%lu atime=%ld",
    + (unsigned long)(curstat->st_dev),
    + (unsigned long)(curstat->st_ino),
    + (long)curstat->st_atime));
    + }
    +
    + if (oldstat && curstat) {
    + if (oldstat->st_dev == curstat->st_dev &&
    + oldstat->st_ino == curstat->st_ino) {
    + if (oldstat->st_atime == curstat->st_atime){
    + DPRINT(Debug,13,(&Debug,", time stampt not updated"));
    + if (use_lastread_auto == use_lastread) {
    + may_create = last_read_def_create;
    + DPRINT(Debug,13,(&Debug,", use last read"));
    + }
    + } else if (oldstat->st_atime < curstat->st_atime) {
    + DPRINT(Debug,13,(&Debug,", time stamp advanced"));
    + }
    + } else {
    + DPRINT(Debug,13,(&Debug,", file changed"));
    + }
    + }
    +
    + DPRINT(Debug,13,(&Debug,"; sys_dir=%s\n",sys_dir));
    +
    + last_read_loc = last_read_dir_to_loc(sys_dir,&res_dir);
    +
    + DPRINT(Debug,13,(&Debug,
    + "last_read_enabled: sys_dir=%s => location %d",
    + sys_dir,
    + last_read_loc));
    +
    + switch (last_read_loc) {
    + case read_loc_none: DPRINT(Debug,13,(&Debug," read_loc_none\n")); goto fail;
    + case read_loc_dir: DPRINT(Debug,13,(&Debug," read_loc_dir")); break;
    + case read_loc_def: DPRINT(Debug,13,(&Debug," read_loc_def")); break;
    + }
    +
    + if (res_dir) {
    + DPRINT(Debug,13,(&Debug,", res_dir=%s",res_dir));
    + }
    + DPRINT(Debug,13,(&Debug,"\n"));
    +
    + if (read_loc_dir == last_read_loc) {
    +
    + enum syscall_status r = access(sys_dir,WRITE_ACCESS|EXECUTE_ACCESS);
    +
    + switch (r) {
    + int err UNUSED_VAROK;
    + case syscall_error /* -1 */:
    + err = errno;
    +
    + DPRINT(Debug,10,(&Debug,
    + "last_read_enabled: No write access (and search) for %s: %s (errno=%d)\n",

    [continued in next message]

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)