diff --git a/daemon/lookup.c b/daemon/lookup.c index 7ea26dc..9f43795 100644 --- a/daemon/lookup.c +++ b/daemon/lookup.c @@ -80,10 +80,12 @@ static void init_component_args( args->attr_request.count = 2; args->attr_request.arr[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE - | FATTR4_WORD0_FSID | FATTR4_WORD0_FILEID; + | FATTR4_WORD0_FSID | FATTR4_WORD0_FILEID + | FATTR4_WORD0_HIDDEN | FATTR4_WORD0_ARCHIVE; args->attr_request.arr[1] = FATTR4_WORD1_MODE - | FATTR4_WORD1_NUMLINKS | FATTR4_WORD1_TIME_ACCESS - | FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_MODIFY; + | FATTR4_WORD1_NUMLINKS | FATTR4_WORD1_SYSTEM + | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_CREATE + | FATTR4_WORD1_TIME_MODIFY; args->getrootattr.attr_request = &args->attr_request; res->root.path = path; diff --git a/daemon/name_cache.c b/daemon/name_cache.c index b75e7fd..a4a3182 100644 --- a/daemon/name_cache.c +++ b/daemon/name_cache.c @@ -90,7 +90,10 @@ struct attr_cache_entry { uint32_t time_create_ns; uint32_t time_modify_ns; uint32_t numlinks; - uint32_t mode; + unsigned mode : 30; + unsigned hidden : 1; + unsigned system : 1; + unsigned archive : 1; time_t expiration; unsigned ref_count : 26; unsigned type : 4; @@ -293,6 +296,10 @@ static void attr_cache_update( } if (info->attrmask.arr[0] & FATTR4_WORD0_SIZE) entry->size = info->size; + if (info->attrmask.arr[0] & FATTR4_WORD0_HIDDEN) + entry->hidden = info->hidden; + if (info->attrmask.arr[0] & FATTR4_WORD0_ARCHIVE) + entry->archive = info->archive; } if (info->attrmask.count >= 2) { if (info->attrmask.arr[1] & FATTR4_WORD1_MODE) @@ -311,6 +318,8 @@ static void attr_cache_update( entry->time_modify_s = info->time_modify.seconds; entry->time_modify_ns = info->time_modify.nseconds; } + if (info->attrmask.arr[1] & FATTR4_WORD1_SYSTEM) + entry->system = info->system; } if (is_delegation(delegation)) @@ -333,13 +342,18 @@ static void copy_attrs( dst->numlinks = src->numlinks; dst->mode = src->mode; dst->fileid = src->fileid; + dst->hidden = src->hidden; + dst->system = src->system; + dst->archive = src->archive; dst->attrmask.count = 2; dst->attrmask.arr[0] = FATTR4_WORD0_TYPE | FATTR4_WORD0_CHANGE - | FATTR4_WORD0_SIZE | FATTR4_WORD0_FILEID; + | FATTR4_WORD0_SIZE | FATTR4_WORD0_FILEID + | FATTR4_WORD0_HIDDEN | FATTR4_WORD0_ARCHIVE; dst->attrmask.arr[1] = FATTR4_WORD1_MODE | FATTR4_WORD1_NUMLINKS | FATTR4_WORD1_TIME_ACCESS - | FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_MODIFY; + | FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_MODIFY + | FATTR4_WORD1_SYSTEM; } diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c index fffcca7..9426702 100644 --- a/daemon/nfs41_ops.c +++ b/daemon/nfs41_ops.c @@ -579,6 +579,8 @@ int nfs41_create( } create_args.name = &file->name; create_args.createattrs = createattrs; + nfs41_superblock_supported_attrs( + parent->fh.superblock, &createattrs->attrmask); compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); getfh_res.fh = &file->fh; @@ -1081,10 +1083,11 @@ void init_getattr_request(bitmap4 *attr_request) { attr_request->count = 2; attr_request->arr[0] = FATTR4_WORD0_TYPE | - FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | FATTR4_WORD0_FILEID; - attr_request->arr[1] = FATTR4_WORD1_NUMLINKS | - FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_CREATE | - FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_MODE; + FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE | + FATTR4_WORD0_FILEID | FATTR4_WORD0_HIDDEN | FATTR4_WORD0_ARCHIVE; + attr_request->arr[1] = FATTR4_WORD1_MODE | FATTR4_WORD1_NUMLINKS | + FATTR4_WORD1_SYSTEM | FATTR4_WORD1_TIME_ACCESS | + FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_MODIFY; attr_request->arr[2] = 0; } diff --git a/daemon/nfs41_types.h b/daemon/nfs41_types.h index 61d46a3..c5bad79 100644 --- a/daemon/nfs41_types.h +++ b/daemon/nfs41_types.h @@ -225,6 +225,8 @@ typedef struct __nfs41_file_info { uint32_t lease_time; /* XXX: per-server */ uint32_t fs_layout_types; /* pnfs, XXX: per-fs */ bool_t hidden; + bool_t system; + bool_t archive; bool_t cansettime; /* XXX: per-fs */ bool_t case_insensitive; bool_t case_preserving; diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c index a23d8b4..b45eea0 100644 --- a/daemon/nfs41_xdr.c +++ b/daemon/nfs41_xdr.c @@ -1755,6 +1755,10 @@ static bool_t decode_file_attrs( if (!xdr_u_int32_t(xdr, &info->aclsupport)) return FALSE; } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_ARCHIVE) { + if (!xdr_bool(xdr, &info->archive)) + return FALSE; + } if (attrs->attrmask.arr[0] & FATTR4_WORD0_CANSETTIME) { if (!xdr_bool(xdr, &info->cansettime)) return FALSE; @@ -1775,6 +1779,10 @@ static bool_t decode_file_attrs( if (!decode_fs_locations4(xdr, info->fs_locations)) return FALSE; } + if (attrs->attrmask.arr[0] & FATTR4_WORD0_HIDDEN) { + if (!xdr_bool(xdr, &info->hidden)) + return FALSE; + } if (attrs->attrmask.arr[0] & FATTR4_WORD0_MAXREAD) { if (!xdr_u_hyper(xdr, &info->maxread)) return FALSE; @@ -1821,6 +1829,10 @@ static bool_t decode_file_attrs( if (!xdr_u_hyper(xdr, &info->space_total)) return FALSE; } + if (attrs->attrmask.arr[1] & FATTR4_WORD1_SYSTEM) { + if (!xdr_bool(xdr, &info->system)) + return FALSE; + } if (attrs->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS) { if (!xdr_nfstime4(xdr, &info->time_access)) return FALSE; @@ -2574,6 +2586,11 @@ static bool_t encode_file_attrs( return FALSE; attrs->attrmask.arr[0] |= FATTR4_WORD0_ACL; } + if (info->attrmask.arr[0] & FATTR4_WORD0_ARCHIVE) { + if (!xdr_bool(&localxdr, &info->archive)) + return FALSE; + attrs->attrmask.arr[0] |= FATTR4_WORD0_ARCHIVE; + } if (info->attrmask.arr[0] & FATTR4_WORD0_HIDDEN) { if (!xdr_bool(&localxdr, &info->hidden)) return FALSE; @@ -2586,6 +2603,11 @@ static bool_t encode_file_attrs( return FALSE; attrs->attrmask.arr[1] |= FATTR4_WORD1_MODE; } + if (info->attrmask.arr[1] & FATTR4_WORD1_SYSTEM) { + if (!xdr_bool(&localxdr, &info->system)) + return FALSE; + attrs->attrmask.arr[1] |= FATTR4_WORD1_SYSTEM; + } if (info->attrmask.arr[1] & FATTR4_WORD1_TIME_ACCESS_SET) { if (!xdr_settime4(&localxdr, &info->time_access, info->time_delta)) return FALSE; diff --git a/daemon/open.c b/daemon/open.c index 7198cef..4104e4f 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -587,10 +587,23 @@ static int handle_open(nfs41_upcall *upcall) nfs41_file_info createattrs; uint32_t create = 0, createhowmode = 0, lookup_status = status; + if (!lookup_status && (args->disposition == FILE_OVERWRITE || + args->disposition == FILE_OVERWRITE_IF || + args->disposition == FILE_SUPERSEDE)) { + if ((info.hidden && !(args->file_attrs & FILE_ATTRIBUTE_HIDDEN)) || + (info.system && !(args->file_attrs & FILE_ATTRIBUTE_SYSTEM))) { + status = ERROR_ACCESS_DENIED; + goto out_free_state; + } + args->mode = info.mode; + } createattrs.attrmask.count = 2; - createattrs.attrmask.arr[0] = 0; - createattrs.attrmask.arr[1] = FATTR4_WORD1_MODE; + createattrs.attrmask.arr[0] = FATTR4_WORD0_HIDDEN | FATTR4_WORD0_ARCHIVE; + createattrs.attrmask.arr[1] = FATTR4_WORD1_MODE | FATTR4_WORD1_SYSTEM; createattrs.mode = args->mode; + createattrs.hidden = args->file_attrs & FILE_ATTRIBUTE_HIDDEN ? 1 : 0; + createattrs.system = args->file_attrs & FILE_ATTRIBUTE_SYSTEM ? 1 : 0; + createattrs.archive = args->file_attrs & FILE_ATTRIBUTE_ARCHIVE ? 1 : 0; map_access_2_allowdeny(args->access_mask, args->access_mode, args->disposition, &state->share_access, &state->share_deny); @@ -626,8 +639,9 @@ supersede_retry: &state->parent, &state->file, &info); args->created = status == NFS4_OK ? TRUE : FALSE; } else { - createattrs.attrmask.arr[0] = FATTR4_WORD0_SIZE; + createattrs.attrmask.arr[0] |= FATTR4_WORD0_SIZE; createattrs.size = 0; + dprintf(1, "creating with mod %o\n", args->mode); status = open_or_delegate(state, create, createhowmode, &createattrs, TRUE, &info); if (status == NFS4_OK && state->delegation.state) diff --git a/daemon/readdir.c b/daemon/readdir.c index e9dc26d..c210234 100644 --- a/daemon/readdir.c +++ b/daemon/readdir.c @@ -482,7 +482,7 @@ static int handle_readdir(nfs41_upcall *upcall) goto out; } - entry_buf = malloc(max_buf_len); + entry_buf = calloc(max_buf_len, sizeof(unsigned char)); if (entry_buf == NULL) { status = GetLastError(); goto out_free_cookie; diff --git a/daemon/setattr.c b/daemon/setattr.c index c5855f8..ca655bd 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -66,8 +66,11 @@ static int handle_nfs41_setattr(setattr_upcall_args *args) /* hidden */ info.hidden = basic_info->FileAttributes & FILE_ATTRIBUTE_HIDDEN ? 1 : 0; - info.attrmask.arr[0] |= FATTR4_WORD0_HIDDEN; - info.attrmask.count = 1; + info.system = basic_info->FileAttributes & FILE_ATTRIBUTE_SYSTEM ? 1 : 0; + info.archive = basic_info->FileAttributes & FILE_ATTRIBUTE_ARCHIVE ? 1 : 0; + info.attrmask.arr[0] |= FATTR4_WORD0_HIDDEN | FATTR4_WORD0_ARCHIVE; + info.attrmask.arr[1] = FATTR4_WORD1_SYSTEM; + info.attrmask.count = 2; if (superblock->cansettime) { /* set the time_delta so xdr_settime4() can decide diff --git a/daemon/util.c b/daemon/util.c index dd42175..f8ce1e4 100644 --- a/daemon/util.c +++ b/daemon/util.c @@ -150,7 +150,9 @@ ULONG nfs_file_info_to_attributes( if (info->mode == 0444) /* XXX: 0444 for READONLY */ attrs |= FILE_ATTRIBUTE_READONLY; - /* TODO: FILE_ATTRIBUTE_HIDDEN */ + if (info->hidden) attrs |= FILE_ATTRIBUTE_HIDDEN; + if (info->system) attrs |= FILE_ATTRIBUTE_SYSTEM; + if (info->archive) attrs |= FILE_ATTRIBUTE_ARCHIVE; // FILE_ATTRIBUTE_NORMAL attribute is only set if no other attributes are present. // all other override this value. diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 4bd97b9..a81e368 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -3533,6 +3533,8 @@ NTSTATUS nfs41_Create( entry->u.Open.access_mask = params.DesiredAccess; entry->u.Open.access_mode = params.ShareAccess; entry->u.Open.attrs = params.FileAttributes; + if (!(params.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + entry->u.Open.attrs |= FILE_ATTRIBUTE_ARCHIVE; entry->u.Open.disp = params.Disposition; entry->u.Open.copts = params.CreateOptions; entry->u.Open.srv_open = SrvOpen;