windows differentiates between directory and file symlinks because a file can have both FILE_ATTRIBUTE_DIRECTORY and FILE_ATTRIBUTE_REPARSE_POINT flags. nfs can only be one of NF4REG/DIR/LNK, so we have to do a readlink and look up the target file for symlinks to know whether or not to set the directory attribute flag. this is done recursively when we encounter links to links
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
added check in handle_open() to avoid calling CREATE/OPEN when we're creating a symlink:
if (args->disposition == FILE_CREATE &&
args->access_mask == (FILE_WRITE_ATTRIBUTES | SYNCHRONIZE | DELETE) &&
args->access_mode == 0 &&
args->create_opts & FILE_OPEN_REPARSE_POINT)
these are the open arguments we get from the CreateSymbolicLink() syscall. by avoiding the call to CREATE/OPEN on handle_open(), we save ourselves from having to REMOVE the file before creating the symlink
added a check to handle_symlink() in case the file was actually created on open (an application could open the file with different arguments, and send the FSCTL_SET_REPARSE_POINT manually), and removes the file first
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
driver handles FSCTL_SET_REPARSE_POINT by sending a symlink set upcall
daemon handles symlink set upcall by calling nfs41_create()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
added optional symlink argument to nfs41_create(), used when type is NF4LNK
changed createttype4.u.lnk.linkdata from char[] to const char* and updated encoding in nfs41_xdr.c
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
no longer depends on nfs41_open_state or open_upcall_args
renamed to nfs41_symlink_follow() and added prototype to nfs41_ops.h
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
getattr upcall for FileAttributeTagInformation sets ReparseTag=IO_REPARSE_TAG_SYMLINK
readdir upcall sets EaSize=IO_REPARSE_TAG_SYMLINK; this makes the 'dir' command show files as <SYMLINK>, and causes a FSCTL_GET_REPARSE_POINT to query the symlink target
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when we fork a thread to handle the callback, the arguments we got from
parsing the callback operations in the callback thread are on the stack.
we need to allocate memory for same-size data structure and copy them,
not just copy the pointer.
/* we shouldn't ever see this, but a buggy server could
* send us into an infinite loop. return NFS4ERR_IO */
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
added nfs41_abs_path symlink to struct open_upcall_args. we can't write the symlink target back to args->path anymore, since it's a pointer into the upcall buffer
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
in handle_mount(), the call to nfs41_lookup() requires a mutable nfs41_abs_path because it can change on referrals, so make a copy for it
removed unused fields in struct nfs41_root and related arguments to nfs41_root_create()
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
because we no longer have to convert strings from unicode, we can avoid copying them out of the upcall buffer
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when open parsing fails, we were still returning upcall.status==NO_ERROR, so the driver assumed the open succeeded. other operations then sent up an open_state==NULL, and crashed the daemon. when upcall_parse() returns an error, set upcall.status to notify the driver
upcall_parse() prints a 'parsing of upcall <name> failed with <error>.' message on failure, so i removed redundant messages from the individual upcall parsing functions
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
when handle_open() encounters a file of type NF4LNK and the FILE_OPEN_REPARSE_POINT flag is not present, it calls READLINK for the symlink's target path. it then calls abs_path_link() to update the filename (args->path), whether the symlink target is an absolute or relative path. abs_path_link() also takes into account the special characters . and .., though it doesn't allow traversing .. entries below the root of the server's namespace
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
on last_error == ERROR_REPARSE, the daemon converts args->path back to wchar and passes it down to the driver
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
caused memory leaks of nfs41_open_state. we have the FileDispositionInformation upcall for exactly this, so there's no need to complicate the close code path
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
if readdir fails to look up a referred entry, set its type to NF4DIR so windows explorer shows it as a directory. when you double-click on the directory, it gives a message saying that it "refers to a location that is unavailable"
Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
moved the FileSystemName definition back down to the kernel, so the daemon is no longer responsible for setting it. the driver uses the string length to calculate the buffer size needed for NFS41_V_NET_ROOT_EXTENSION.FsAttrs, and copies in the FileSystemName after the first successful volume attributes upcall
Signed-off-by: Casey Bodley <cbodley@umich.edu>
added time_delta argument to xdr_settime4(). if the normal 'time' argument is within time_delta of the current time (get_nfs_time()), it uses time_how=SET_TO_SERVER_TIME4. otherwise, it uses SET_TO_CLIENT_TIME4 and encodes the time as usual
handle_nfs41_setattr() ignores times if superblock->cansettime==0. otherwise, it passes in superblock->time_delta (via info.time_delta) along with the other time attributes, for use with xdr_settime4()
Signed-off-by: Casey Bodley <cbodley@umich.edu>
added FILE_FS_ATTRIBUTE_INFORMATION and FileSystemAttributes flags to from_kernel.h
queries case_preserving, case_insensitive attributes to fill in FileSystemAttributes, and uses #defines from nfs41_const.h for MaximumComponentNameLength and FileSystemName
Signed-off-by: Casey Bodley <cbodley@umich.edu>
added FS_INFORMATION_CLASS, FILE_FS_SIZE_INFORMATION, FILE_FS_FULL_SIZE_INFORMATION to from_kernel.h
moved get_volume_size_info() and byte->unit conversion up to the daemon
Signed-off-by: Casey Bodley <cbodley@umich.edu>
symptom: in certain cases, name_cache_find_or_create() was returning ERROR_FILE_EXISTS, which should never happen!
cause: the string comparisons in name_cache_search() and name_cache_insert() were returning different results when the argument to name_cache_search() is a) not null-terminated, and b) shorter than the other string. this caused name_cache_search() to search the wrong branch of the rbtree and fail to find the component, while name_cache_insert() would correctly find it and return ERROR_FILE_EXISTS
fix: compare the string lengths before calling strncmp() to avoid comparing past the end of the component. moved the comparisons to a separate component_cmp() function called by both name_cache_search() and name_cache_insert() to make sure they get the same result!
Signed-off-by: Casey Bodley <cbodley@umich.edu>
the link part of basic test7 was failing because LINK's target was still cached as a negative entry, leading to the error "can't stat newfile.0 after link". the solution is to replace the negative entry with the real fh and attributes of the target file
so instead of doing RESTOREFH+GETATTR on the source file and calling nfs41_attr_cache_update(), nfs41_link() uses LOOKUP+GETATTR+GETFH to get attributes for the target file and passes them to nfs41_name_cache_insert() along with dst_dir's changeinfo. because the source and target file will have the same fileid attribute, nfs41_name_cache_insert() will update the attributes of both at the same time. added the target file as an optional return parameter
Signed-off-by: Casey Bodley <cbodley@umich.edu>
/* negative lookup caching
*
* by caching lookups that result in NOENT, we can avoid sending subsequent
* lookups over the wire. a name cache entry is negative when its attributes
* pointer is NULL. negative entries are created by three functions:
* nfs41_name_cache_remove(), _insert() when called with NULL for the fh and
* attributes, and _rename() for the source entry
*/
Signed-off-by: Casey Bodley <cbodley@umich.edu>