From 6e443f948b757214cebed8d798ee332912a16767 Mon Sep 17 00:00:00 2001 From: Sam Liddicott Date: Wed, 12 Nov 2008 08:35:32 +0000 Subject: [PATCH] TEMP: rollup of case-instensitve compare hack and fix qpathinfo --- source4/ntvfs/proxy/vfs_proxy.c | 259 +++++++++++++++++++++++++++++++--------- 1 file changed, 203 insertions(+), 56 deletions(-) diff --git a/source4/ntvfs/proxy/vfs_proxy.c b/source4/ntvfs/proxy/vfs_proxy.c index 614baa87169..6bf7d1d1aa1 100644 --- a/source4/ntvfs/proxy/vfs_proxy.c +++ b/source4/ntvfs/proxy/vfs_proxy.c @@ -48,6 +48,10 @@ #include "lib/compression/zlib.h" #include "libcli/raw/raw_proto.h" #include "librpc/gen_ndr/proxy.h" +#include "smb_server/smb_server.h" + +#define fstrcmp(a,b) strcasecmp((a),(b)) +#define fstrncmp(a,b,len) strncasecmp((a),(b),(len)) #define LOAD_CACHE_FILE_DATA(dest, src) do { \ dest.create_time=src.create_time; \ @@ -127,6 +131,7 @@ struct file_metadata { struct proxy_file { struct proxy_file *prev, *next; + struct proxy_private* proxy; uint16_t fnum; struct ntvfs_handle *h; struct cache_file_entry *cache; @@ -173,6 +178,28 @@ enum search_cache_status { SEARCH_CACHE_COMPLETE, SEARCH_CACHE_DEAD }; + +struct fdirmon; +typedef void*(fdirmon_callback_fn)(void* data, struct fdirmon* fdirmon); +//NTSTATUS (*fn)(struct async_info*, void*, void*, NTSTATUS) + +struct fdirmon { + struct fdirmon *prev, *next; + struct search_cache_item *items; + + struct proxy_private *proxy; + + union smb_notify *notify_io; + struct smbcli_request *notify_req; + uint16_t dir_fnum; + char* dir; + struct fdirmon_callback { + struct fdirmon_callback *prev, *next; + fdirmon_callback_fn *fn; + void* data; + } *callbacks; +}; + struct search_cache { struct search_cache *prev, *next; struct search_cache_item *items; @@ -216,6 +243,8 @@ struct proxy_private { struct ntvfs_module_context *ntvfs; struct async_info *pending; struct proxy_file *files; + struct proxy_file *closed_files; + struct fdirmon *dirmons; struct search_cache *search_caches; /* cache's of find-first data */ struct search_handle *search_handles; /* cache's of find-first data */ bool map_generic; @@ -392,7 +421,7 @@ struct smb_wire_string talloc_smb_wire_string_dup(void* mem_ctx, const struct sm static char* talloc_dirname(void* mem_ctx, const char* path) { const char* dir; - if (dir=strrchr(path,'\\')) { + if ((dir=strrchr(path,'\\'))) { return talloc_strndup(mem_ctx, path, (dir - path)); } else { return talloc_strdup(mem_ctx,""); @@ -804,6 +833,121 @@ static void async_simple(struct smbcli_request *c_req) } \ } while(0) +static void async_dirmon_notify(struct smbcli_request *c_req) +{ + struct async_info *async = c_req->async.private; + struct ntvfs_request *req = async->req; + struct fdirmon *dirmon; + struct fdirmon_callback *callback; + struct proxy_private *proxy = async->proxy; + + NTSTATUS status; + + DEBUG(5,("%s: dirmon %p invalidated\n",__LOCATION__, (void*)async->f)); + + dirmon = talloc_get_type_abort((void*)async->f, struct fdirmon); + + status = smb_raw_changenotify_recv(c_req, req, async->parms); + DEBUG(5,("%s: update status %s\n",__LOCATION__, get_friendly_nt_error_msg (status))); + + dirmon->notify_req=NULL; + DLIST_FOR_EACH(dirmon->callbacks, callback, callback->fn(callback->data, dirmon)); + /* So nothing can find it even if there are still in-use references */ + DLIST_REMOVE(proxy->dirmons, dirmon); + /* free it */ + //talloc_steal(async, search_cache); + talloc_free(async); + talloc_free(dirmon); +} + +struct fdirmon* get_fdirmon(struct proxy_private *proxy, const char* path, bool dir_only) { + const char *file; + int pathlen; + + if ((file=strrchr(path,'\\'))) { + if (dir_only) { + pathlen = file - path; + file++; + } else { + pathlen=strlen(path); + } + } else { + file = path; + pathlen = 0; + } + + struct fdirmon *dirmon; + /* see if we have a matching dirmon */ + DLIST_FIND(proxy->dirmons, dirmon, (strlen(dirmon->dir) == pathlen && fstrncmp(path, dirmon->dir, pathlen)==0)); + if (! dirmon) { + int saved_timeout; + + dirmon=talloc_zero(proxy, struct fdirmon); + if (! dirmon) { + goto error; + } + if (! (dirmon->dir=talloc_strndup(dirmon, path, pathlen))) { + goto error; + } + if (! (dirmon->notify_io=talloc_zero(dirmon, union smb_notify))) { + goto error; + } + + dirmon->dir_fnum=smbcli_nt_create_full(proxy->tree, dirmon->dir, + 0, + SEC_FILE_READ_DATA, + FILE_ATTRIBUTE_NORMAL, + NTCREATEX_SHARE_ACCESS_MASK, + NTCREATEX_DISP_OPEN, + NTCREATEX_OPTIONS_DIRECTORY, + NTCREATEX_IMPERSONATION_IMPERSONATION); + if (dirmon->dir_fnum==65535) { + goto error; + } + + saved_timeout = proxy->transport->options.request_timeout; + /* request notify changes on cache before we start to fill it */ + dirmon->notify_io->nttrans.level=RAW_NOTIFY_NTTRANS; + dirmon->notify_io->nttrans.in.completion_filter=FILE_NOTIFY_CHANGE_ANY; + dirmon->notify_io->nttrans.in.file.fnum=dirmon->dir_fnum; + dirmon->notify_io->nttrans.in.recursive=false; + dirmon->notify_io->nttrans.in.buffer_size=1024; + proxy->transport->options.request_timeout = 0; + dirmon->notify_req=smb_raw_changenotify_send(proxy->tree, dirmon->notify_io); + /* Make the request hang around so we can tell if it needs cancelling */ + talloc_reference(dirmon, dirmon->notify_req); + proxy->transport->options.request_timeout = saved_timeout; + + if (! dirmon->notify_req) { + goto error; + }else { + struct ntvfs_request *req=NULL; + struct smbcli_request *c_req=dirmon->notify_req; + union smb_notify *io=dirmon->notify_io; + struct proxy_private *private=proxy; + ASYNC_RECV_TAIL_F_ORPHAN_NE(io, async_dirmon_notify, + (void*) dirmon, c_req->async.private); + DLIST_ADD(private->dirmons, dirmon); + } + } + + return dirmon; + error: + talloc_free(dirmon); + return NULL; +} + +bool dirmon_add_callback(struct fdirmon *dirmon, fdirmon_callback_fn *fn, void* data) { + struct fdirmon_callback *callback=talloc_zero(dirmon, struct fdirmon_callback); + if (! callback) { + return false; + } + callback->data=data; + callback->fn=fn; + DLIST_ADD(dirmon->callbacks, callback); + return true; +} + /* try and unify cache open function interface with this macro */ #define cache_open(cache_context, f, io, oplock, readahead_window) \ (io->generic.level == RAW_OPEN_NTCREATEX && \ @@ -819,7 +963,7 @@ struct search_cache* find_partial_search_cache(struct search_cache* search_cache (result->key.search_attrib == search_cache_key->search_attrib) && (result->key.flags == search_cache_key->flags) && (result->key.storage_type == search_cache_key->storage_type) && - (strcmp(result->key.pattern, search_cache_key->pattern) == 0)); + (fstrcmp(result->key.pattern, search_cache_key->pattern) == 0)); DEBUG(5,("%s: found %p\n",__LOCATION__,result)); return result; } @@ -835,7 +979,7 @@ struct search_cache* find_search_cache(struct search_cache* search_cache, const uint16_t smbsrv_fnum(struct ntvfs_handle *h) { uint16_t fnum; - smbsrv_push_fnum(&fnum, 0, h); + smbsrv_push_fnum((uint8_t *)&fnum, 0, h); return SVAL(&fnum, 0); } @@ -1063,7 +1207,7 @@ static bool find_search_cache_item(const char* path, /* see if we can satisfy from a directory cache */ DEBUG(5,("%s: Looking for pathinfo: '%s'\n",__LOCATION__,path)); - if (file=strrchr(path,'\\')) { + if ((file=strrchr(path,'\\'))) { dir_len = file - path; /* point past the \ */ file++; @@ -1082,7 +1226,7 @@ static bool find_search_cache_item(const char* path, /* One day we may support all directory levels */ DLIST_FIND(s, s, (s->key.data_level == RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO && strlen(s->dir)==dir_len && - strncmp(s->dir, path, dir_len)==0)); + fstrncmp(s->dir, path, dir_len)==0)); if (! s) { break; } @@ -1090,9 +1234,9 @@ static bool find_search_cache_item(const char* path, /* search s for io->generic.in.file.path */ DLIST_FIND(s->items, i, (i->data_level == RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO && ((i->file->both_directory_info.name.s && - strcmp(i->file->both_directory_info.name.s, file) ==0) || + fstrcmp(i->file->both_directory_info.name.s, file) ==0) || (i->file->both_directory_info.short_name.s && - strcmp(i->file->both_directory_info.short_name.s, file)==0) + fstrcmp(i->file->both_directory_info.short_name.s, file)==0) ))); DEBUG(5,("%s: found cache %p item %p\n",__LOCATION__,s, i)); if (i) { @@ -1108,7 +1252,7 @@ static bool find_search_cache_item(const char* path, return false; } -static proxy_set_cache_info(struct file_metadata *metadata, struct proxy_GetInfo *r) { +static void proxy_set_cache_info(struct file_metadata *metadata, struct proxy_GetInfo *r) { if (NT_STATUS_IS_OK(r->out.info_data[0].status_RAW_FILEINFO_BASIC_INFORMATION) || NT_STATUS_IS_OK(r->out.info_data[0].status_RAW_FILEINFO_ALL_INFO)) { metadata->info_data.create_time=r->out.info_data[0].create_time; @@ -1296,7 +1440,7 @@ static NTSTATUS async_proxy_qpathinfo(struct async_info *async, void* io1, void* struct proxy_private *private = async->proxy; struct smbcli_request *c_req = async->c_req; struct ntvfs_request *req = async->req; - struct search_cache_item *item = talloc_get_type_abort(async->f, struct search_cache_item); + struct proxy_file *f = talloc_get_type_abort(async->f, struct proxy_file); union smb_fileinfo *io = talloc_get_type_abort(io1, union smb_fileinfo); struct proxy_GetInfo *r=talloc_get_type_abort(io2, struct proxy_GetInfo); @@ -1310,14 +1454,22 @@ static NTSTATUS async_proxy_qpathinfo(struct async_info *async, void* io1, void* SMB_ASSERT(r->out.count==1); NT_STATUS_NOT_OK_RETURN(r->out.info_data[0].status); - DEBUG(5,("%s: will set cache_info %p %p %p\n",__LOCATION__,item, item?item->metadata:NULL, r)); - proxy_set_cache_info(item->metadata, r); + DEBUG(5,("%s: will set cache %p item=%p metadata=%p %p\n",__LOCATION__,f, f?f->metadata:NULL, r)); + proxy_set_cache_info(f->metadata, r); - req->async_states->status=proxy_cache_info(io, item->metadata, NULL); + req->async_states->status=proxy_cache_info(io, f->metadata, NULL); return req->async_states->status; } +static void async_qpathinfo_notify(void* data, struct fdirmon* dirmon) { + struct proxy_file* file=data; + + DEBUG(5,("%s: qpathinfo cache %s destroyed\n",__LOCATION__,file->filename)); + DLIST_REMOVE(file->proxy->closed_files, file); + talloc_free(file); +} + /* return info on a pathname */ @@ -1326,23 +1478,20 @@ static NTSTATUS proxy_qpathinfo(struct ntvfs_module_context *ntvfs, { struct proxy_private *private = ntvfs->private_data; struct smbcli_request *c_req; - struct search_cache *s=private->search_caches; - struct search_cache_item *item=NULL; + struct proxy_file *f=NULL; const char* path; SETUP_PID; + /* Look for closed files */ if (private->enabled_qpathinfo) { + int len=strlen(io->generic.in.file.path)+1; DEBUG(5,("%s: Looking for cached metadata for: %s\n",__LOCATION__,io->generic.in.file.path)); - while(s && !item) { - if (find_search_cache_item(io->generic.in.file.path, &s, &item) - && item->metadata) { - break; - } - } - if (item && s) { + DLIST_FIND(private->closed_files, f, + (len==f->filename_size && fstrncmp(io->generic.in.file.path, f->filename, f->filename_size)==0)); + if (f) { /* stop cache going away while we are using it */ - talloc_reference(req, s); + talloc_reference(req, f); } } /* upgrade the request */ @@ -1362,34 +1511,30 @@ static NTSTATUS proxy_qpathinfo(struct ntvfs_module_context *ntvfs, case RAW_FILEINFO_STREAM_INFORMATION: case RAW_FILEINFO_EA_INFO: case RAW_FILEINFO_EA_INFORMATION: - DEBUG(5,("%s: item is %p\n",__FUNCTION__, item)); - if (s && item && item->metadata) { + DEBUG(5,("%s: item is %p\n",__FUNCTION__, f)); + if (f && f->metadata) { NTSTATUS status; bool valid; - DEBUG(5,("%s: %p Using cached metadata %x (item=%p)\n",__FUNCTION__, s, item->metadata->valid, item)); - status=proxy_cache_info(io, item->metadata, &valid); + DEBUG(5,("%s: Using cached metadata %x (item=%p)\n",__FUNCTION__, f->metadata->valid, f)); + status=proxy_cache_info(io, f->metadata, &valid); if (valid) return status; DEBUG(5,("%s: But cached metadata not valid :-(\n",__FUNCTION__)); } /* construct an item to hold the cache if we need to */ - if (! item && private->enabled_cache_info && PROXY_REMOTE_SERVER(private)) { - struct search_cache_key key; - key.level=RAW_FILEINFO_BASIC_INFORMATION; - key.data_level=RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO; - key.search_attrib=FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY; - key.pattern=io->generic.in.file.path; - s=new_search_cache(private, &key); - if (s && (item=talloc_zero(s, struct search_cache_item))) { - DLIST_ADD(s->items, item); - s->status=SEARCH_CACHE_COMPLETE; - } else { - talloc_free(s); - } - } - if (item && ! item->metadata) { - item->metadata=talloc_zero(item, struct file_metadata); + if (! f && private->enabled_cache_info && PROXY_REMOTE_SERVER(private) && (f=talloc_zero(private, struct proxy_file))) { + struct fdirmon* dirmon; + dirmon=get_fdirmon(private, io->generic.in.file.path, true); + f->proxy=private; + dirmon_add_callback(dirmon, async_qpathinfo_notify, f); + + f->filename=talloc_strdup(f, io->generic.in.file.path); + f->filename_size=strlen(f->filename)+1; + f->metadata=talloc_zero(f, struct file_metadata); + /* should not really add unless we succeeded */ + DLIST_ADD(private->closed_files, f); + } - if (item && item->metadata && private->enabled_cache_info && PROXY_REMOTE_SERVER(private)) { + if (f && f->metadata && private->enabled_cache_info && PROXY_REMOTE_SERVER(private)) { struct proxy_GetInfo *r; DEBUG(5,("%s: promoting request to proxy\n",__FUNCTION__)); @@ -1404,7 +1549,7 @@ static NTSTATUS proxy_qpathinfo(struct ntvfs_module_context *ntvfs, r->in.info_tags[0].info_tag.path.s=io->generic.in.file.path; c_req = smbcli_ndr_request_ntioctl_send(private->tree, ntvfs, &ndr_table_rpcproxy, NDR_PROXY_GETINFO, r); /* the callback handler will populate the cache and respond from the cache */ - ADD_ASYNC_RECV_TAIL(c_req, io, r, (void*)item, async_proxy_qpathinfo, NT_STATUS_INTERNAL_ERROR); + ADD_ASYNC_RECV_TAIL(c_req, io, r, f, async_proxy_qpathinfo, NT_STATUS_INTERNAL_ERROR); if (! (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { DEBUG(5,("%s Sync waiting promotion\n",__FUNCTION__)); @@ -1665,6 +1810,7 @@ static NTSTATUS proxy_open(struct ntvfs_module_context *ntvfs, f = talloc_zero(h, struct proxy_file); NT_STATUS_HAVE_NO_MEMORY(f); + f->proxy=private; /* If the file is being opened read only and we already have a read-only handle for this file, then just clone and ref-count the handle */ @@ -3112,6 +3258,7 @@ static NTSTATUS proxy_close(struct ntvfs_module_context *ntvfs, return NT_STATUS_OK; } DEBUG(5,("%s: Real close of %d\n",__FUNCTION__, f->fnum)); + cache_close(f->cache); /* possibly samba can't do RAW_CLOSE_SEND yet */ if (! (c_req = smb_raw_close_send(private->tree, io))) { @@ -3618,7 +3765,7 @@ static NTSTATUS proxy_search_first(struct ntvfs_module_context *ntvfs, //s->resume_item = state->last_item; }*/ /* destroy handle */ - DEBUG(5,("%s: Removing handle %x\n",__LOCATION__,h)); + DEBUG(5,("%s: Removing handle %p\n",__LOCATION__,h)); ntvfs_handle_remove_backend_data(h, ntvfs); io->t2ffirst.out.handle=0; } else { @@ -3686,35 +3833,35 @@ static NTSTATUS proxy_search_next(struct ntvfs_module_context *ntvfs, break; case RAW_SEARCH_DATA_DIRECTORY_INFO: /* TODO: maybe these should be strcasecmp for some filesystems */ DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->directory_info.name.s)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->directory_info.name.s)==0); break; case RAW_SEARCH_DATA_FULL_DIRECTORY_INFO: DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->full_directory_info.name.s)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->full_directory_info.name.s)==0); break; case RAW_SEARCH_DATA_NAME_INFO: DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->name_info.name.s)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->name_info.name.s)==0); break; case RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO: DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->both_directory_info.name.s)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->both_directory_info.name.s)==0); break; case RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO: DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->id_full_directory_info.name.s)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->id_full_directory_info.name.s)==0); break; case RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO: DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->id_both_directory_info.name.s)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->id_both_directory_info.name.s)==0); break; case RAW_SEARCH_DATA_UNIX_INFO: DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->unix_info.name)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->unix_info.name)==0); break; case RAW_SEARCH_DATA_UNIX_INFO2: DEBUG(5,("%s: type %x seek on %s\n",__LOCATION__, io->generic.data_level, io->t2fnext.in.last_name)); - DLIST_FIND_NEXT(search_cache->items, start_at, strcmp(io->t2fnext.in.last_name, start_at->file->unix_info2.name.s)==0); + DLIST_FIND_NEXT(search_cache->items, start_at, fstrcmp(io->t2fnext.in.last_name, start_at->file->unix_info2.name.s)==0); break; default: if (io->t2fnext.in.flags & FLAG_TRANS2_FIND_CONTINUE) { @@ -3765,7 +3912,7 @@ static NTSTATUS proxy_search_next(struct ntvfs_module_context *ntvfs, io->t2fnext.in.flags & FLAG_TRANS2_FIND_CLOSE) { /* destroy handle */ - DEBUG(5,("%s: Removing handle %x\n",__LOCATION__,h)); + DEBUG(5,("%s: Removing handle %p\n",__LOCATION__,h)); ntvfs_handle_remove_backend_data(h, ntvfs); } @@ -3804,7 +3951,7 @@ static NTSTATUS proxy_search_next(struct ntvfs_module_context *ntvfs, }*/ } /* destroy handle */ - DEBUG(5,("%s: Removing handle %x\n",__LOCATION__,h)); + DEBUG(5,("%s: Removing handle %p\n",__LOCATION__,h)); ntvfs_handle_remove_backend_data(h, ntvfs); } io->t2fnext.out.count=state->count; @@ -4454,7 +4601,7 @@ static NTSTATUS rpclite_proxy_Getinfo(struct ntvfs_module_context *ntvfs, // ADD_ASYNC_RECV_TAIL(c_req, r, NULL, f, rpclite_proxy_Getinfo_map_async_send, NT_STATUS_INTERNAL_ERROR); if (! (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) { - DEBUG(5,("Sync waiting for nttrans response\n",__FUNCTION__)); + DEBUG(5,("%s:Sync waiting for nttrans response\n",__LOCATION__)); return sync_chain_handler(c_req); } else { ASYNC_RECV_TAIL_HANDLER_ORPHAN(io, async_chain_handler); -- 2.11.4.GIT