symlink: nfs41_symlink_follow() for readdir and open
added nfs41_file_info.symlink_dir to replace readdir's info.cansettime hack. when nfs_file_info_to_attributes() finds info.type==NF4LNK, it adds the FILE_ATTRIBUTE_DIRECTORY flag if info.symlink_dir is set renamed nfs41_symlink_follow() to nfs41_symlink_target() generalized lookup_symlink() into nfs41_symlink_follow(), which is called by readdir and open (also avoids an extra lookup) added queries for symlink target type when doing normal GETATTRs (getattr.c) and opens with OPEN_REPARSE_POINT set (open.c) Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
parent
a8f66804d5
commit
eb9d9bbd4c
7 changed files with 80 additions and 36 deletions
|
|
@ -93,6 +93,14 @@ int handle_getattr(nfs41_upcall *upcall)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.type == NF4LNK) {
|
||||||
|
nfs41_file_info target_info;
|
||||||
|
int target_status = nfs41_symlink_follow(args->root,
|
||||||
|
state->session, &state->file, &target_info);
|
||||||
|
if (target_status == NO_ERROR && target_info.type == NF4DIR)
|
||||||
|
info.symlink_dir = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
switch (args->query_class) {
|
switch (args->query_class) {
|
||||||
case FileBasicInformation:
|
case FileBasicInformation:
|
||||||
nfs_to_basic_info(&info, &args->basic_info);
|
nfs_to_basic_info(&info, &args->basic_info);
|
||||||
|
|
|
||||||
|
|
@ -1022,11 +1022,17 @@ int nfs41_link(
|
||||||
OUT OPTIONAL nfs41_path_fh *link_out);
|
OUT OPTIONAL nfs41_path_fh *link_out);
|
||||||
|
|
||||||
/* symlink.c */
|
/* symlink.c */
|
||||||
int nfs41_symlink_follow(
|
int nfs41_symlink_target(
|
||||||
IN nfs41_session *session,
|
IN nfs41_session *session,
|
||||||
IN nfs41_path_fh *file,
|
IN nfs41_path_fh *file,
|
||||||
OUT nfs41_abs_path *target);
|
OUT nfs41_abs_path *target);
|
||||||
|
|
||||||
|
int nfs41_symlink_follow(
|
||||||
|
IN nfs41_root *root,
|
||||||
|
IN nfs41_session *session,
|
||||||
|
IN nfs41_path_fh *symlink,
|
||||||
|
OUT nfs41_file_info *info);
|
||||||
|
|
||||||
int nfs41_readlink(
|
int nfs41_readlink(
|
||||||
IN nfs41_session *session,
|
IN nfs41_session *session,
|
||||||
IN nfs41_path_fh *file,
|
IN nfs41_path_fh *file,
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,7 @@ typedef struct __nfs41_file_info {
|
||||||
bool_t cansettime; /* XXX: per-fs */
|
bool_t cansettime; /* XXX: per-fs */
|
||||||
bool_t case_insensitive;
|
bool_t case_insensitive;
|
||||||
bool_t case_preserving;
|
bool_t case_preserving;
|
||||||
|
bool_t symlink_dir;
|
||||||
} nfs41_file_info;
|
} nfs41_file_info;
|
||||||
|
|
||||||
#endif /* !__NFS41_DAEMON_TYPES_H__ */
|
#endif /* !__NFS41_DAEMON_TYPES_H__ */
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ int handle_open(nfs41_upcall *upcall)
|
||||||
int status = 0;
|
int status = 0;
|
||||||
open_upcall_args *args = &upcall->args.open;
|
open_upcall_args *args = &upcall->args.open;
|
||||||
nfs41_open_state *state;
|
nfs41_open_state *state;
|
||||||
nfs41_file_info info;
|
nfs41_file_info info = { 0 };
|
||||||
|
|
||||||
status = create_open_state(args->path, args->open_owner_id, &state);
|
status = create_open_state(args->path, args->open_owner_id, &state);
|
||||||
if (status) {
|
if (status) {
|
||||||
|
|
@ -242,7 +242,7 @@ int handle_open(nfs41_upcall *upcall)
|
||||||
args->symlink_embedded = TRUE;
|
args->symlink_embedded = TRUE;
|
||||||
|
|
||||||
/* replace the path with the symlink target */
|
/* replace the path with the symlink target */
|
||||||
status = nfs41_symlink_follow(state->session,
|
status = nfs41_symlink_target(state->session,
|
||||||
&state->parent, &args->symlink);
|
&state->parent, &args->symlink);
|
||||||
goto out_free_state;
|
goto out_free_state;
|
||||||
}
|
}
|
||||||
|
|
@ -270,14 +270,20 @@ int handle_open(nfs41_upcall *upcall)
|
||||||
} else if (info.type == NF4LNK) {
|
} else if (info.type == NF4LNK) {
|
||||||
dprintf(2, "handle nfs41_open: SYMLINK\n");
|
dprintf(2, "handle nfs41_open: SYMLINK\n");
|
||||||
if (args->create_opts & FILE_OPEN_REPARSE_POINT) {
|
if (args->create_opts & FILE_OPEN_REPARSE_POINT) {
|
||||||
/* continue and open the symlink itself */
|
/* continue and open the symlink itself, but we need to
|
||||||
|
* know if the target is a regular file or directory */
|
||||||
|
nfs41_file_info target_info;
|
||||||
|
int target_status = nfs41_symlink_follow(args->root,
|
||||||
|
state->session, &state->file, &target_info);
|
||||||
|
if (target_status == NO_ERROR && target_info.type == NF4DIR)
|
||||||
|
info.symlink_dir = TRUE;
|
||||||
} else {
|
} else {
|
||||||
/* tell the driver to call RxPrepareToReparseSymbolicLink() */
|
/* tell the driver to call RxPrepareToReparseSymbolicLink() */
|
||||||
upcall->last_error = ERROR_REPARSE;
|
upcall->last_error = ERROR_REPARSE;
|
||||||
args->symlink_embedded = FALSE;
|
args->symlink_embedded = FALSE;
|
||||||
|
|
||||||
/* replace the path with the symlink target */
|
/* replace the path with the symlink target */
|
||||||
status = nfs41_symlink_follow(state->session,
|
status = nfs41_symlink_target(state->session,
|
||||||
&state->file, &args->symlink);
|
&state->file, &args->symlink);
|
||||||
goto out_free_state;
|
goto out_free_state;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -170,10 +170,6 @@ static void readdir_copy_dir_info(
|
||||||
entry->attr_info.size;
|
entry->attr_info.size;
|
||||||
info->fdi.FileAttributes = nfs_file_info_to_attributes(
|
info->fdi.FileAttributes = nfs_file_info_to_attributes(
|
||||||
&entry->attr_info);
|
&entry->attr_info);
|
||||||
|
|
||||||
/* use cansettime to flag the symlink target as a directory */
|
|
||||||
if (entry->attr_info.cansettime)
|
|
||||||
info->fdi.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readdir_copy_shortname(
|
static void readdir_copy_shortname(
|
||||||
|
|
@ -249,7 +245,7 @@ static int lookup_entry(
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
name.name = entry->name;
|
name.name = entry->name;
|
||||||
name.len = (unsigned short)entry->name_len;
|
name.len = (unsigned short)entry->name_len - 1;
|
||||||
|
|
||||||
status = format_abs_path(parent->path, &name, &path);
|
status = format_abs_path(parent->path, &name, &path);
|
||||||
if (status) goto out;
|
if (status) goto out;
|
||||||
|
|
@ -269,7 +265,7 @@ static int lookup_symlink(
|
||||||
OUT nfs41_file_info *info_out)
|
OUT nfs41_file_info *info_out)
|
||||||
{
|
{
|
||||||
nfs41_abs_path path;
|
nfs41_abs_path path;
|
||||||
nfs41_path_fh link_parent, file;
|
nfs41_path_fh file;
|
||||||
nfs41_file_info info;
|
nfs41_file_info info;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
|
|
@ -277,28 +273,15 @@ static int lookup_symlink(
|
||||||
if (status) goto out;
|
if (status) goto out;
|
||||||
|
|
||||||
file.path = &path;
|
file.path = &path;
|
||||||
/* get a filehandle for the symlink */
|
status = nfs41_lookup(root, session, &path, NULL, &file, &info, &session);
|
||||||
status = nfs41_lookup(root, session, &path, NULL, &file, &info, NULL);
|
|
||||||
if (status) goto out;
|
if (status) goto out;
|
||||||
|
|
||||||
link_parent.path = &path;
|
|
||||||
last_component(path.path, path.path + path.len, &file.name);
|
last_component(path.path, path.path + path.len, &file.name);
|
||||||
last_component(path.path, file.name.name, &link_parent.name);
|
|
||||||
|
|
||||||
/* attempt to follow the symlink */
|
status = nfs41_symlink_follow(root, session, &file, &info);
|
||||||
status = nfs41_symlink_follow(session, &file, &path);
|
|
||||||
if (status) goto out;
|
if (status) goto out;
|
||||||
|
|
||||||
/* get attributes for the target */
|
info_out->symlink_dir = info.type == NF4DIR;
|
||||||
status = nfs41_lookup(root, session, &path, &link_parent, NULL, &info, NULL);
|
|
||||||
if (status) goto out;
|
|
||||||
|
|
||||||
if (info.type == NF4LNK) {
|
|
||||||
status = lookup_symlink(root, session, &link_parent, &file.name, &info);
|
|
||||||
if (status) goto out;
|
|
||||||
info_out->cansettime = info.cansettime;
|
|
||||||
} else if (info.type == NF4DIR)
|
|
||||||
info_out->cansettime = 1;
|
|
||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,6 @@ static int abs_path_link(
|
||||||
const char *link_end = link + link_len;
|
const char *link_end = link + link_len;
|
||||||
int status = NO_ERROR;
|
int status = NO_ERROR;
|
||||||
|
|
||||||
dprintf(2, "--> abs_path_link('%s', '%s')\n", path->path, link);
|
|
||||||
|
|
||||||
/* if link is an absolute path, start path_pos at the beginning */
|
/* if link is an absolute path, start path_pos at the beginning */
|
||||||
if (is_delimiter(*link))
|
if (is_delimiter(*link))
|
||||||
path_pos = path->path;
|
path_pos = path->path;
|
||||||
|
|
@ -91,11 +89,10 @@ static int abs_path_link(
|
||||||
*path_pos = '\0';
|
*path_pos = '\0';
|
||||||
out:
|
out:
|
||||||
path->len = (unsigned short)(path_pos - path->path);
|
path->len = (unsigned short)(path_pos - path->path);
|
||||||
dprintf(2, "<-- abs_path_link('%s') returning %d\n", path->path, status);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfs41_symlink_follow(
|
int nfs41_symlink_target(
|
||||||
IN nfs41_session *session,
|
IN nfs41_session *session,
|
||||||
IN nfs41_path_fh *file,
|
IN nfs41_path_fh *file,
|
||||||
OUT nfs41_abs_path *target)
|
OUT nfs41_abs_path *target)
|
||||||
|
|
@ -114,6 +111,8 @@ int nfs41_symlink_follow(
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dprintf(2, "--> nfs41_symlink_target('%s', '%s')\n", path->path, link);
|
||||||
|
|
||||||
/* overwrite the last component of the path; get the starting offset */
|
/* overwrite the last component of the path; get the starting offset */
|
||||||
path_offset = file->name.name - path->path;
|
path_offset = file->name.name - path->path;
|
||||||
|
|
||||||
|
|
@ -127,7 +126,6 @@ int nfs41_symlink_follow(
|
||||||
status = abs_path_link(target, target->path + path_offset, link, link_len);
|
status = abs_path_link(target, target->path + path_offset, link, link_len);
|
||||||
if (status) {
|
if (status) {
|
||||||
eprintf("abs_path_link() failed with %d\n", status);
|
eprintf("abs_path_link() failed with %d\n", status);
|
||||||
status = ERROR_PATH_NOT_FOUND;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -139,6 +137,44 @@ int nfs41_symlink_follow(
|
||||||
}
|
}
|
||||||
target->len = (unsigned short)strlen(target->path);
|
target->len = (unsigned short)strlen(target->path);
|
||||||
out:
|
out:
|
||||||
|
dprintf(2, "<-- nfs41_symlink_target('%s') returning %d\n",
|
||||||
|
target->path, status);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nfs41_symlink_follow(
|
||||||
|
IN nfs41_root *root,
|
||||||
|
IN nfs41_session *session,
|
||||||
|
IN nfs41_path_fh *symlink,
|
||||||
|
OUT nfs41_file_info *info)
|
||||||
|
{
|
||||||
|
nfs41_abs_path path;
|
||||||
|
nfs41_path_fh file;
|
||||||
|
int status = NO_ERROR;
|
||||||
|
|
||||||
|
file.path = &path;
|
||||||
|
InitializeSRWLock(&path.lock);
|
||||||
|
|
||||||
|
dprintf(2, "--> nfs41_symlink_follow('%s')\n", symlink->path->path);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* construct the target path */
|
||||||
|
status = nfs41_symlink_target(session, symlink, &path);
|
||||||
|
if (status) goto out;
|
||||||
|
|
||||||
|
dprintf(2, "looking up '%s'\n", path.path);
|
||||||
|
|
||||||
|
last_component(path.path, path.path + path.len, &file.name);
|
||||||
|
|
||||||
|
/* get attributes for the target */
|
||||||
|
status = nfs41_lookup(root, session, &path,
|
||||||
|
NULL, &file, info, &session);
|
||||||
|
if (status) goto out;
|
||||||
|
|
||||||
|
symlink = &file;
|
||||||
|
} while (info->type == NF4LNK);
|
||||||
|
out:
|
||||||
|
dprintf(2, "<-- nfs41_symlink_follow() returning %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,9 +130,11 @@ ULONG nfs_file_info_to_attributes(
|
||||||
ULONG attrs = 0;
|
ULONG attrs = 0;
|
||||||
if (info->type == NF4DIR)
|
if (info->type == NF4DIR)
|
||||||
attrs |= FILE_ATTRIBUTE_DIRECTORY;
|
attrs |= FILE_ATTRIBUTE_DIRECTORY;
|
||||||
else if (info->type == NF4LNK)
|
else if (info->type == NF4LNK) {
|
||||||
attrs |= FILE_ATTRIBUTE_REPARSE_POINT;
|
attrs |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
else if (info->type != NF4REG)
|
if (info->symlink_dir)
|
||||||
|
attrs |= FILE_ATTRIBUTE_DIRECTORY;
|
||||||
|
} else if (info->type != NF4REG)
|
||||||
dprintf(1, "unhandled file type %d, defaulting to NF4REG\n",
|
dprintf(1, "unhandled file type %d, defaulting to NF4REG\n",
|
||||||
info->type);
|
info->type);
|
||||||
|
|
||||||
|
|
@ -162,11 +164,13 @@ void nfs_to_standard_info(
|
||||||
IN const nfs41_file_info *info,
|
IN const nfs41_file_info *info,
|
||||||
OUT PFILE_STANDARD_INFO std_out)
|
OUT PFILE_STANDARD_INFO std_out)
|
||||||
{
|
{
|
||||||
|
const ULONG FileAttributes = nfs_file_info_to_attributes(info);
|
||||||
|
|
||||||
std_out->AllocationSize.QuadPart =
|
std_out->AllocationSize.QuadPart =
|
||||||
std_out->EndOfFile.QuadPart = (LONGLONG)info->size;
|
std_out->EndOfFile.QuadPart = (LONGLONG)info->size;
|
||||||
std_out->NumberOfLinks = info->numlinks;
|
std_out->NumberOfLinks = info->numlinks;
|
||||||
std_out->DeletePending = FALSE;
|
std_out->DeletePending = FALSE;
|
||||||
std_out->Directory = info->type == NF4DIR ? TRUE : FALSE;
|
std_out->Directory = FileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue