r6146: Added OS/2 EA support in trans2_open and trans2_mkdir. Fixed in nttrans_create.
[samba.git] / source / smbd / trans2.c
index ca2c8a060dcbf590245a7d381fc5b20c7f0f666e..a68b165cb0088fd81cd74a7eaf3d97d93806ecc9 100644 (file)
@@ -23,9 +23,8 @@
 
 #include "includes.h"
 
-extern int Protocol;
+extern enum protocol_types Protocol;
 extern int smb_read_error;
-extern fstring local_machine;
 extern int global_oplock_break;
 extern uint32 global_client_caps;
 extern struct current_user current_user;
@@ -34,16 +33,18 @@ extern struct current_user current_user;
 #define DIR_ENTRY_SAFETY_MARGIN 4096
 
 /********************************************************************
- Roundup a value to the nearest SMB_ROUNDUP_ALLOCATION_SIZE boundary.
+ Roundup a value to the nearest allocation roundup size boundary.
  Only do this for Windows clients.
 ********************************************************************/
 
-SMB_BIG_UINT smb_roundup(SMB_BIG_UINT val)
+SMB_BIG_UINT smb_roundup(connection_struct *conn, SMB_BIG_UINT val)
 {
+       SMB_BIG_UINT rval = lp_allocation_roundup_size(SNUM(conn));
+
        /* Only roundup for Windows clients. */
        enum remote_arch_types ra_type = get_remote_arch();
-       if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
-               val = SMB_ROUNDUP(val,SMB_ROUNDUP_ALLOCATION_SIZE);
+       if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
+               val = SMB_ROUNDUP(val,rval);
        }
        return val;
 }
@@ -53,7 +54,7 @@ SMB_BIG_UINT smb_roundup(SMB_BIG_UINT val)
  account sparse files.
 ********************************************************************/
 
-SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf)
+SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, SMB_STRUCT_STAT *sbuf)
 {
        SMB_BIG_UINT ret;
 
@@ -66,9 +67,7 @@ SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf)
        if (!ret && fsp && fsp->initial_allocation_size)
                ret = fsp->initial_allocation_size;
 
-       ret = smb_roundup(ret);
-
-       return ret;
+       return smb_roundup(conn, ret);
 }
 
 /****************************************************************************
@@ -96,11 +95,6 @@ static BOOL samba_private_attr_name(const char *unix_ea_name)
        return False;
 }
 
-struct ea_list {
-       struct ea_list *next, *prev;
-       struct ea_struct ea;
-};
-
 /****************************************************************************
  Get one EA value. Fill in a struct ea_struct.
 ****************************************************************************/
@@ -115,7 +109,7 @@ static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
 
  again:
 
-       val = talloc_realloc(mem_ctx, val, attr_size);
+       val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
        if (!val) {
                return False;
        }
@@ -144,7 +138,7 @@ static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
        } else {
                pea->name = ea_name;
        }
-       pea->value.data = val;
+       pea->value.data = (unsigned char *)val;
        pea->value.length = (size_t)sizeret;
        return True;
 }
@@ -153,7 +147,8 @@ static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
  Return a linked list of the total EA's. Plus the total size
 ****************************************************************************/
 
-static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp, const char *fname, size_t *pea_total_len)
+static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
+                                       const char *fname, size_t *pea_total_len)
 {
        /* Get a list of all xattrs. Max namesize is 64k. */
        size_t ea_namelist_size = 1024;
@@ -169,8 +164,8 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
                return NULL;
        }
 
-       for (i = 0, ea_namelist = talloc(mem_ctx, ea_namelist_size); i < 6;
-                       ea_namelist = talloc_realloc(mem_ctx, ea_namelist, ea_namelist_size), i++) {
+       for (i = 0, ea_namelist = TALLOC(mem_ctx, ea_namelist_size); i < 6;
+                       ea_namelist = TALLOC_REALLOC_ARRAY(mem_ctx, ea_namelist, char, ea_namelist_size), i++) {
                if (fsp && fsp->fd != -1) {
                        sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fd, ea_namelist, ea_namelist_size);
                } else {
@@ -187,7 +182,7 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
        if (sizeret == -1)
                return NULL;
 
-       DEBUG(10,("get_ea_list: ea_namelist size = %d\n", sizeret ));
+       DEBUG(10,("get_ea_list_from_file: ea_namelist size = %d\n", sizeret ));
 
        if (sizeret) {
                for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p) + 1) {
@@ -196,7 +191,7 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
                        if (strnequal(p, "system.", 7) || samba_private_attr_name(p))
                                continue;
                
-                       listp = talloc(mem_ctx, sizeof(struct ea_list));
+                       listp = TALLOC_P(mem_ctx, struct ea_list);
                        if (!listp)
                                return NULL;
 
@@ -208,7 +203,7 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
                                fstring dos_ea_name;
                                push_ascii_fstring(dos_ea_name, listp->ea.name);
                                *pea_total_len += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
-                               DEBUG(10,("get_ea_list: total_len = %u, %s, val len = %u\n",
+                               DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len = %u\n",
                                        *pea_total_len, dos_ea_name,
                                        (unsigned int)listp->ea.value.length ));
                        }
@@ -220,7 +215,7 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
                }
        }
 
-       DEBUG(10,("get_ea_list: total_len = %u\n", *pea_total_len));
+       DEBUG(10,("get_ea_list_from_file: total_len = %u\n", *pea_total_len));
        return ea_list_head;
 }
 
@@ -229,34 +224,16 @@ static struct ea_list *get_ea_list(TALLOC_CTX *mem_ctx, connection_struct *conn,
  that was filled.
 ****************************************************************************/
 
-static unsigned int fill_ea_buffer(char *pdata, unsigned int total_data_size,
-       connection_struct *conn, files_struct *fsp, const char *fname)
+static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
+       connection_struct *conn, struct ea_list *ea_list)
 {
        unsigned int ret_data_size = 4;
        char *p = pdata;
-       size_t total_ea_len;
-       TALLOC_CTX *mem_ctx;
-       struct ea_list *ea_list;
 
        SMB_ASSERT(total_data_size >= 4);
 
-       SIVAL(pdata,0,0);
        if (!lp_ea_support(SNUM(conn))) {
-               return 4;
-       }
-       mem_ctx = talloc_init("fill_ea_buffer");
-       if (!mem_ctx) {
-               return 4;
-       }
-
-       ea_list = get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len);
-       if (!ea_list) {
-               talloc_destroy(mem_ctx);
-               return 4;
-       }
-
-       if (total_ea_len > total_data_size) {
-               talloc_destroy(mem_ctx);
+               SIVAL(pdata,4,0);
                return 4;
        }
 
@@ -287,9 +264,7 @@ static unsigned int fill_ea_buffer(char *pdata, unsigned int total_data_size,
        }
 
        ret_data_size = PTR_DIFF(p, pdata);
-       DEBUG(10,("fill_ea_buffer: data_size = %u, total_ea_len = %u\n",
-                       ret_data_size, total_ea_len ));
-       talloc_destroy(mem_ctx);
+       DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
        SIVAL(pdata,0,ret_data_size);
        return ret_data_size;
 }
@@ -303,7 +278,7 @@ static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp,
                return 0;
        }
        mem_ctx = talloc_init("estimate_ea_size");
-       (void)get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len);
+       (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
        talloc_destroy(mem_ctx);
        return total_ea_len;
 }
@@ -316,7 +291,7 @@ static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, con
 {
        size_t total_ea_len;
        TALLOC_CTX *mem_ctx = talloc_init("canonicalize_ea_name");
-       struct ea_list *ea_list = get_ea_list(mem_ctx, conn, fsp, fname, &total_ea_len);
+       struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
 
        for (; ea_list; ea_list = ea_list->next) {
                if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
@@ -333,99 +308,246 @@ static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, con
  Set or delete an extended attribute.
 ****************************************************************************/
 
-static NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname,
-                       char *pdata, int total_data)
+NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, struct ea_list *ea_list)
 {
-       unsigned int namelen;
-       unsigned int ealen;
-       int ret;
-       fstring unix_ea_name;
-
        if (!lp_ea_support(SNUM(conn))) {
                return NT_STATUS_EAS_NOT_SUPPORTED;
        }
 
-       if (total_data < 8) {
-               return NT_STATUS_INVALID_PARAMETER;
+       for (;ea_list; ea_list = ea_list->next) {
+               int ret;
+               fstring unix_ea_name;
+
+               fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
+               fstrcat(unix_ea_name, ea_list->ea.name);
+
+               canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
+
+               DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, ea_list->ea.value.length));
+
+               if (samba_private_attr_name(unix_ea_name)) {
+                       DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
+                       return NT_STATUS_ACCESS_DENIED;
+               }
+
+               if (ea_list->ea.value.length == 0) {
+                       /* Remove the attribute. */
+                       if (fsp && (fsp->fd != -1)) {
+                               DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n",
+                                       unix_ea_name, fsp->fsp_name));
+                               ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, unix_ea_name);
+                       } else {
+                               DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
+                                       unix_ea_name, fname));
+                               ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
+                       }
+#ifdef ENOATTR
+                       /* Removing a non existent attribute always succeeds. */
+                       if (ret == -1 && errno == ENOATTR) {
+                               DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
+                                               unix_ea_name));
+                               ret = 0;
+                       }
+#endif
+               } else {
+                       if (fsp && (fsp->fd != -1)) {
+                               DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n",
+                                       unix_ea_name, fsp->fsp_name));
+                               ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, unix_ea_name,
+                                                       ea_list->ea.value.data, ea_list->ea.value.length, 0);
+                       } else {
+                               DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
+                                       unix_ea_name, fname));
+                               ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
+                                                       ea_list->ea.value.data, ea_list->ea.value.length, 0);
+                       }
+               }
+
+               if (ret == -1) {
+#ifdef ENOTSUP
+                       if (errno == ENOTSUP) {
+                               return NT_STATUS_EAS_NOT_SUPPORTED;
+                       }
+#endif
+                       return map_nt_error_from_unix(errno);
+               }
+
        }
+       return NT_STATUS_OK;
+}
+/****************************************************************************
+ Read a list of EA names from an incoming data buffer. Create an ea_list with them.
+****************************************************************************/
+
+static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+{
+       struct ea_list *ea_list_head = NULL;
+       size_t offset = 0;
+
+       while (offset + 2 < data_size) {
+               struct ea_list *tmp;
+               struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
+               unsigned int namelen = CVAL(pdata,offset);
+
+               offset++; /* Go past the namelen byte. */
 
-       if (IVAL(pdata,0) > total_data) {
-               DEBUG(10,("set_ea: bad total data size (%u) > %u\n", IVAL(pdata,0), (unsigned int)total_data));
-               return NT_STATUS_INVALID_PARAMETER;
+               /* integer wrap paranioa. */
+               if ((offset + namelen < offset) || (offset + namelen < namelen) ||
+                               (offset > data_size) || (namelen > data_size) ||
+                               (offset + namelen >= data_size)) {
+                       break;
+               }
+               /* Ensure the name is null terminated. */
+               if (pdata[offset + namelen] != '\0') {
+                       return NULL;
+               }
+               pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset]);
+               if (!eal->ea.name) {
+                       return NULL;
+               }
+
+               offset += (namelen + 1); /* Go past the name + terminating zero. */
+               DLIST_ADD_END(ea_list_head, eal, tmp);
+               DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
        }
 
-       pdata += 4;
-       namelen = CVAL(pdata,1);
-       ealen = SVAL(pdata,2);
-       pdata += 4;
-       if (total_data < 8 + namelen + 1 + ealen) {
-               DEBUG(10,("set_ea: bad total data size (%u) < 8 + namelen (%u) + 1 + ealen (%u)\n",
-                       (unsigned int)total_data, namelen, ealen));
-               return NT_STATUS_INVALID_PARAMETER;
+       return ea_list_head;
+}
+
+/****************************************************************************
+ Read one EA list entry from the buffer.
+****************************************************************************/
+
+struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
+{
+       struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
+       uint16 val_len;
+       unsigned int namelen;
+
+       if (!eal) {
+               return NULL;
        }
 
-       if (pdata[namelen] != '\0') {
-               DEBUG(10,("set_ea: ea name not null terminated\n"));
-               return NT_STATUS_INVALID_PARAMETER;
+       if (data_size < 6) {
+               return NULL;
        }
 
-       fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
-       pull_ascii(&unix_ea_name[5], pdata, sizeof(fstring) - 5, -1, STR_TERMINATE);
-       pdata += (namelen + 1);
+       eal->ea.flags = CVAL(pdata,0);
+       namelen = CVAL(pdata,1);
+       val_len = SVAL(pdata,2);
 
-       canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
+       if (4 + namelen + 1 + val_len > data_size) {
+               return NULL;
+       }
 
-       DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, ealen));
-       if (ealen) {
-               DEBUG(10,("set_ea: data :\n"));
-               dump_data(10, pdata, ealen);
+       /* Ensure the name is null terminated. */
+       if (pdata[namelen + 4] != '\0') {
+               return NULL;
+       }
+       pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4);
+       if (!eal->ea.name) {
+               return NULL;
        }
 
-       if (samba_private_attr_name(unix_ea_name)) {
-               DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
-               return NT_STATUS_ACCESS_DENIED;
+       eal->ea.value = data_blob(NULL, (size_t)val_len + 1);
+       if (!eal->ea.value.data) {
+               return NULL;
        }
 
-       if (ealen == 0) {
-               /* Remove the attribute. */
-               if (fsp && (fsp->fd != -1)) {
-                       DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n",
-                               unix_ea_name, fsp->fsp_name));
-                       ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, unix_ea_name);
-               } else {
-                       DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
-                               unix_ea_name, fname));
-                       ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
-               }
-#ifdef ENOATTR
-               /* Removing a non existent attribute always succeeds. */
-               if (ret == -1 && errno == ENOATTR) {
-                       DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n", unix_ea_name));
-                       ret = 0;
-               }
-#endif
-       } else {
-               if (fsp && (fsp->fd != -1)) {
-                       DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n",
-                               unix_ea_name, fsp->fsp_name));
-                       ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, unix_ea_name, pdata, ealen, 0);
-               } else {
-                       DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
-                               unix_ea_name, fname));
-                       ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name, pdata, ealen, 0);
+       memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
+
+       /* Ensure we're null terminated just in case we print the value. */
+       eal->ea.value.data[val_len] = '\0';
+       /* But don't count the null. */
+       eal->ea.value.length--;
+
+       if (pbytes_used) {
+               *pbytes_used = 4 + namelen + 1 + val_len;
+       }
+
+       DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
+       dump_data(10, eal->ea.value.data, eal->ea.value.length);
+
+       return eal;
+}
+
+/****************************************************************************
+ Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
+****************************************************************************/
+
+static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
+{
+       struct ea_list *ea_list_head = NULL;
+       size_t offset = 0;
+       size_t bytes_used = 0;
+
+       while (offset < data_size) {
+               struct ea_list *tmp;
+               struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
+
+               if (!eal) {
+                       return NULL;
                }
+
+               DLIST_ADD_END(ea_list_head, eal, tmp);
+               offset += bytes_used;
        }
 
-       if (ret == -1) {
-#ifdef ENOTSUP
-               if (errno == ENOTSUP) {
-                       return NT_STATUS_EAS_NOT_SUPPORTED;
+       return ea_list_head;
+}
+
+/****************************************************************************
+ Count the total EA size needed.
+****************************************************************************/
+
+static size_t ea_list_size(struct ea_list *ealist)
+{
+       fstring dos_ea_name;
+       struct ea_list *listp;
+       size_t ret = 0;
+
+       for (listp = ealist; listp; listp = listp->next) {
+               push_ascii_fstring(dos_ea_name, listp->ea.name);
+               ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
+       }
+       /* Add on 4 for total length. */
+       if (ret) {
+               ret += 4;
+       }
+
+       return ret;
+}
+
+/****************************************************************************
+ Return a union of EA's from a file list and a list of names.
+ The TALLOC context for the two lists *MUST* be identical as we steal
+ memory from one list to add to another. JRA.
+****************************************************************************/
+
+static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
+{
+       struct ea_list *nlistp, *flistp;
+
+       for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
+               for (flistp = file_list; flistp; flistp = flistp->next) {
+                       if (strequal(nlistp->ea.name, flistp->ea.name)) {
+                               break;
+                       }
+               }
+
+               if (flistp) {
+                       /* Copy the data from this entry. */
+                       nlistp->ea.flags = flistp->ea.flags;
+                       nlistp->ea.value = flistp->ea.value;
+               } else {
+                       /* Null entry. */
+                       nlistp->ea.flags = 0;
+                       ZERO_STRUCT(nlistp->ea.value);
                }
-#endif
-               return map_nt_error_from_unix(errno);
        }
 
-       return NT_STATUS_OK;
+       *total_ea_len = ea_list_size(name_list);
+       return name_list;
 }
 
 /****************************************************************************
@@ -584,9 +706,11 @@ static int send_trans2_replies(char *outbuf,
 ****************************************************************************/
 
 static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
-                          char **pparams, int total_params, char **ppdata, int total_data)
+                               char **pparams, int total_params, char **ppdata, int total_data,
+                               unsigned int max_data_bytes)
 {
        char *params = *pparams;
+       char *pdata = *ppdata;
        int16 open_mode;
        int16 open_attr;
        BOOL oplock_request;
@@ -606,14 +730,17 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        int smb_action = 0;
        BOOL bad_path = False;
        files_struct *fsp;
+       TALLOC_CTX *ctx = NULL;
+       struct ea_list *ea_list = NULL;
        NTSTATUS status;
 
        /*
         * Ensure we have enough parameters to perform the operation.
         */
 
-       if (total_params < 29)
-               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+       if (total_params < 29) {
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
 
        open_mode = SVAL(params, 2);
        open_attr = SVAL(params,6);
@@ -635,7 +762,7 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
                return ERROR_NT(status);
        }
 
-       DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n",
+       DEBUG(3,("call_trans2open %s mode=%d attr=%d ofun=%d size=%d\n",
                fname,open_mode, open_attr, open_ofun, open_size));
 
        /* XXXX we need to handle passed times, sattr and flags */
@@ -649,10 +776,38 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
+       /* Any data in this call is an EA list. */
+       if (total_data && !lp_ea_support(SNUM(conn))) {
+               return ERROR_NT(NT_STATUS_EAS_NOT_SUPPORTED);
+       }
+
+       if (total_data) {
+               if (total_data < 10) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               if (IVAL(pdata,0) > total_data) {
+                       DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
+                               IVAL(pdata,0), (unsigned int)total_data));
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               ctx = talloc_init("TRANS2_OPEN_SET_EA");
+               if (!ctx) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+               ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
+               if (!ea_list) {
+                       talloc_destroy(ctx);
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+       }
+
        fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,(uint32)open_attr,
                oplock_request, &rmode,&smb_action);
       
        if (!fsp) {
+               talloc_destroy(ctx);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
                        clear_cached_errors();
@@ -666,14 +821,25 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        mtime = sbuf.st_mtime;
        inode = sbuf.st_ino;
        if (fmode & aDIR) {
+               talloc_destroy(ctx);
                close_file(fsp,False);
                return(ERROR_DOS(ERRDOS,ERRnoaccess));
        }
 
+       if (total_data && smb_action == FILE_WAS_CREATED) {
+               status = set_ea(conn, fsp, fname, ea_list);
+               talloc_destroy(ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       close_file(fsp,False);
+                       return ERROR_NT(status);
+               }
+       }
+
        /* Realloc the size of parameters and data we will return */
-       params = Realloc(*pparams, 28);
-       if( params == NULL )
-               return(ERROR_DOS(ERRDOS,ERRnomem));
+       params = SMB_REALLOC(*pparams, 28);
+       if( params == NULL ) {
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
 
        memset((char *)params,'\0',28);
@@ -800,21 +966,6 @@ static mode_t unix_perms_from_wire( connection_struct *conn, SMB_STRUCT_STAT *ps
        return ret;
 }
 
-/****************************************************************************
- Checks for SMB_TIME_NO_CHANGE and if not found calls interpret_long_date.
-****************************************************************************/
-
-time_t interpret_long_unix_date(char *p)
-{
-       DEBUG(10,("interpret_long_unix_date\n"));
-       if(IVAL(p,0) == SMB_TIME_NO_CHANGE_LO &&
-          IVAL(p,4) == SMB_TIME_NO_CHANGE_HI) {
-               return -1;
-       } else {
-               return interpret_long_date(p);
-       }
-}
-
 /****************************************************************************
  Get a level dependent lanman2 dir entry.
 ****************************************************************************/
@@ -826,7 +977,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                                 BOOL dont_descend,char **ppdata, 
                                 char *base_data, int space_remaining, 
                                 BOOL *out_of_space, BOOL *got_exact_match,
-                                int *last_name_off)
+                                int *last_entry_off, struct ea_list *name_list, TALLOC_CTX *ea_ctx)
 {
        const char *dname;
        BOOL found = False;
@@ -836,13 +987,14 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
        pstring fname;
        char *p, *q, *pdata = *ppdata;
        uint32 reskey=0;
-       int prev_dirpos=0;
+       long prev_dirpos=0;
        int mode=0;
        SMB_OFF_T file_size = 0;
        SMB_BIG_UINT allocation_size = 0;
        uint32 len;
        time_t mdate=0, adate=0, cdate=0;
        char *nameptr;
+       char *last_entry_ptr;
        BOOL was_8_3;
        int nt_extmode; /* Used for NT connections instead of mode */
        BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
@@ -863,12 +1015,12 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
        } else
                pstrcpy(mask, path_mask);
 
+
        while (!found) {
                BOOL got_match;
-
                /* Needed if we run out of space */
-               prev_dirpos = TellDir(conn->dirptr);
-               dname = ReadDirName(conn->dirptr);
+               long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr);
+               dname = dptr_ReadDirName(conn->dirptr,&curr_dirpos,&sbuf);
 
                /*
                 * Due to bugs in NT client redirectors we are not using
@@ -879,8 +1031,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                reskey = 0;
 
-               DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
-                       (long)conn->dirptr,TellDir(conn->dirptr)));
+               DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n",
+                       (long)conn->dirptr,curr_dirpos));
       
                if (!dname) 
                        return(False);
@@ -922,7 +1074,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                                                pathreal,strerror(errno)));
                                        continue;
                                }
-                       } else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+                       } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
 
                                /* Needed to show the msdfs symlinks as 
                                 * directories */
@@ -945,13 +1097,13 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                        mode = dos_mode(conn,pathreal,&sbuf);
 
-                       if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+                       if (!dir_check_ftype(conn,mode,dirtype)) {
                                DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
                                continue;
                        }
 
                        file_size = get_file_size(sbuf);
-                       allocation_size = get_allocation_size(NULL,&sbuf);
+                       allocation_size = get_allocation_size(conn,NULL,&sbuf);
                        mdate = sbuf.st_mtime;
                        adate = sbuf.st_atime;
                        cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
@@ -962,8 +1114,13 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                                adate &= ~1;
                        }
 
-                       if(mode & aDIR)
+                       if(mode & aDIR) {
+                               /* This is necessary, as otherwise the
+                                * desktop.ini file in this folder is
+                                * ignored */
+                               mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
                                file_size = 0;
+                       }
 
                        DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
          
@@ -974,13 +1131,13 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
        mangle_map(fname,False,True,SNUM(conn));
 
        p = pdata;
-       nameptr = p;
+       last_entry_ptr = p;
 
        nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
 
        switch (info_level) {
-               case SMB_INFO_STANDARD:
-                       DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
+               case SMB_FIND_INFO_STANDARD:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n"));
                        if(requires_resume_key) {
                                SIVAL(p,0,reskey);
                                p += 4;
@@ -1011,8 +1168,8 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        p += len;
                        break;
 
-               case SMB_INFO_QUERY_EA_SIZE:
-                       DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
+               case SMB_FIND_EA_SIZE:
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n"));
                        if(requires_resume_key) {
                                SIVAL(p,0,reskey);
                                p += 4;
@@ -1048,6 +1205,63 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
                        break;
 
+               case SMB_FIND_EA_LIST:
+               {
+                       struct ea_list *file_list = NULL;
+                       size_t ea_len = 0;
+
+                       DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n"));
+                       if (!name_list) {
+                               return False;
+                       }
+                       if(requires_resume_key) {
+                               SIVAL(p,0,reskey);
+                               p += 4;
+                       }
+                       put_dos_date2(p,l2_fdateCreation,cdate);
+                       put_dos_date2(p,l2_fdateLastAccess,adate);
+                       put_dos_date2(p,l2_fdateLastWrite,mdate);
+                       SIVAL(p,l2_cbFile,(uint32)file_size);
+                       SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
+                       SSVAL(p,l2_attrFile,mode);
+                       p += l2_cbList; /* p now points to the EA area. */
+
+                       file_list = get_ea_list_from_file(ea_ctx, conn, NULL, pathreal, &ea_len);
+                       name_list = ea_list_union(name_list, file_list, &ea_len);
+
+                       /* We need to determine if this entry will fit in the space available. */
+                       /* Max string size is 255 bytes. */
+                       if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
+                               /* Move the dirptr back to prev_dirpos */
+                               dptr_SeekDir(conn->dirptr, prev_dirpos);
+                               *out_of_space = True;
+                               DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
+                               return False; /* Not finished - just out of space */
+                       }
+
+                       /* Push the ea_data followed by the name. */
+                       p += fill_ea_buffer(ea_ctx, p, space_remaining, conn, name_list);
+                       nameptr = p;
+                       len = srvstr_push(outbuf, p + 1, fname, -1, STR_TERMINATE | STR_NOALIGN);
+                       if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
+                               if (len > 2) {
+                                       len -= 2;
+                               } else {
+                                       len = 0;
+                               }
+                       } else {
+                               if (len > 1) {
+                                       len -= 1;
+                               } else {
+                                       len = 0;
+                               }
+                       }
+                       SCVAL(nameptr,0,len);
+                       p += len + 1;
+                       SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
+                       break;
+               }
+
                case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
                        DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
                        was_8_3 = mangle_is_8_3(fname, True);
@@ -1242,7 +1456,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        SOFF_T(p,0,get_file_size(sbuf));             /* File size 64 Bit */
                        p+= 8;
 
-                       SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
+                       SOFF_T(p,0,get_allocation_size(conn,NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
                        p+= 8;
 
                        put_long_date(p,sbuf.st_ctime);       /* Inode change Time 64 Bit */
@@ -1298,14 +1512,14 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
        if (PTR_DIFF(p,pdata) > space_remaining) {
                /* Move the dirptr back to prev_dirpos */
-               SeekDir(conn->dirptr, prev_dirpos);
+               dptr_SeekDir(conn->dirptr, prev_dirpos);
                *out_of_space = True;
                DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
                return False; /* Not finished - just out of space */
        }
 
-       /* Setup the last_filename pointer, as an offset from base_data */
-       *last_name_off = PTR_DIFF(nameptr,base_data);
+       /* Setup the last entry pointer, as an offset from base_data */
+       *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
        /* Advance the data pointer to the next slot */
        *ppdata = p;
 
@@ -1317,14 +1531,14 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 ****************************************************************************/
 
 static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
-                               char **pparams, int total_params, char **ppdata, int total_data)
+                               char **pparams, int total_params, char **ppdata, int total_data,
+                               unsigned int max_data_bytes)
 {
        /* We must be careful here that we don't return more than the
                allowed number of data bytes. If this means returning fewer than
                maxentries then so be it. We assume that the redirector has
                enough room for the fixed number of parameter bytes it has
                requested. */
-       uint32 max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *params = *pparams;
        char *pdata = *ppdata;
        int dirtype = SVAL(params,0);
@@ -1336,8 +1550,8 @@ static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outb
        int info_level = SVAL(params,6);
        pstring directory;
        pstring mask;
-       char *p, *wcard;
-       int last_name_off=0;
+       char *p;
+       int last_entry_off=0;
        int dptr_num = -1;
        int numentries = 0;
        int i;
@@ -1347,10 +1561,13 @@ static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outb
        int space_remaining;
        BOOL bad_path = False;
        SMB_STRUCT_STAT sbuf;
+       TALLOC_CTX *ea_ctx = NULL;
+       struct ea_list *ea_list = NULL;
        NTSTATUS ntstatus = NT_STATUS_OK;
 
-       if (total_params < 12)
-               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+       if (total_params < 12) {
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
 
        *directory = *mask = 0;
 
@@ -1365,8 +1582,9 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
        }
  
        switch (info_level) {
-               case SMB_INFO_STANDARD:
-               case SMB_INFO_QUERY_EA_SIZE:
+               case SMB_FIND_INFO_STANDARD:
+               case SMB_FIND_EA_SIZE:
+               case SMB_FIND_EA_LIST:
                case SMB_FIND_FILE_DIRECTORY_INFO:
                case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
                case SMB_FIND_FILE_NAMES_INFO:
@@ -1387,7 +1605,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                return ERROR_NT(ntstatus);
        }
 
-       RESOLVE_FINDFIRST_DFSPATH(directory, conn, inbuf, outbuf);
+       RESOLVE_DFSPATH_WCARD(directory, conn, inbuf, outbuf);
 
        unix_convert(directory,conn,0,&bad_path,&sbuf);
        if (bad_path) {
@@ -1412,35 +1630,69 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
 
        DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
 
-       pdata = Realloc(*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
-       if( pdata == NULL )
-               return(ERROR_DOS(ERRDOS,ERRnomem));
+       if (info_level == SMB_FIND_EA_LIST) {
+               uint32 ea_size;
+
+               if (total_data < 4) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               ea_size = IVAL(pdata,0);
+               if (ea_size != total_data) {
+                       DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
+total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               if (!lp_ea_support(SNUM(conn))) {
+                       return ERROR_DOS(ERRDOS,ERReasnotsupported);
+               }
+                                                                                                                                                        
+               if ((ea_ctx = talloc_init("findnext_ea_list")) == NULL) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+                                                                                                                                                        
+               /* Pull out the list of names. */
+               ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
+               if (!ea_list) {
+                       talloc_destroy(ea_ctx);
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+       }
+
+       pdata = SMB_REALLOC(*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
+       if( pdata == NULL ) {
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
 
        *ppdata = pdata;
        memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
 
        /* Realloc the params space */
-       params = Realloc(*pparams, 10);
-       if (params == NULL)
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       params = SMB_REALLOC(*pparams, 10);
+       if (params == NULL) {
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
 
        dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
-       if (dptr_num < 0)
+       if (dptr_num < 0) {
+               talloc_destroy(ea_ctx);
                return(UNIXERROR(ERRDOS,ERRbadfile));
+       }
 
        /* Save the wildcard match and attribs we are using on this directory - 
                needed as lanman2 assumes these are being saved between calls */
 
-       if(!(wcard = strdup(mask))) {
+       if (!dptr_set_wcard_and_attributes(dptr_num, mask, dirtype)) {
                dptr_close(&dptr_num);
-               return ERROR_DOS(ERRDOS,ERRnomem);
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
 
-       dptr_set_wcard(dptr_num, wcard);
-       dptr_set_attr(dptr_num, dirtype);
-
-       DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
+       DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, mask, dirtype));
 
        /* We don't need to check for VOL here as this is returned by 
                a different TRANS2 call. */
@@ -1467,7 +1719,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                                        mask,dirtype,info_level,
                                        requires_resume_key,dont_descend,
                                        &p,pdata,space_remaining, &out_of_space, &got_exact_match,
-                                       &last_name_off);
+                                       &last_entry_off, ea_list, ea_ctx);
                }
 
                if (finished && out_of_space)
@@ -1489,6 +1741,8 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
                space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
        }
   
+       talloc_destroy(ea_ctx);
+
        /* Check if we can close the dirptr */
        if(close_after_first || (finished && close_if_end)) {
                DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
@@ -1497,12 +1751,18 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
 
        /* 
         * If there are no matching entries we must return ERRDOS/ERRbadfile - 
-        * from observation of NT.
+        * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
+        * the protocol level is less than NT1. Tested with smbclient. JRA.
+        * This should fix the OS/2 client bug #2335.
         */
 
        if(numentries == 0) {
                dptr_close(&dptr_num);
-               return ERROR_DOS(ERRDOS,ERRbadfile);
+               if (Protocol < PROTOCOL_NT1) {
+                       return ERROR_DOS(ERRDOS,ERRnofiles);
+               } else {
+                       return ERROR_BOTH(NT_STATUS_NO_SUCH_FILE,ERRDOS,ERRbadfile);
+               }
        }
 
        /* At this point pdata points to numentries directory entries. */
@@ -1512,7 +1772,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
        SSVAL(params,2,numentries);
        SSVAL(params,4,finished);
        SSVAL(params,6,0); /* Never an EA error */
-       SSVAL(params,8,last_name_off);
+       SSVAL(params,8,last_entry_off);
 
        send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata));
 
@@ -1542,14 +1802,14 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
 ****************************************************************************/
 
 static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        /* We must be careful here that we don't return more than the
                allowed number of data bytes. If this means returning fewer than
                maxentries then so be it. We assume that the redirector has
                enough room for the fixed number of parameter bytes it has
                requested. */
-       int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *params = *pparams;
        char *pdata = *ppdata;
        int dptr_num = SVAL(params,0);
@@ -1567,21 +1827,34 @@ static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbu
        char *p;
        uint16 dirtype;
        int numentries = 0;
-       int i, last_name_off=0;
+       int i, last_entry_off=0;
        BOOL finished = False;
        BOOL dont_descend = False;
        BOOL out_of_space = False;
        int space_remaining;
+       TALLOC_CTX *ea_ctx = NULL;
+       struct ea_list *ea_list = NULL;
        NTSTATUS ntstatus = NT_STATUS_OK;
 
-       if (total_params < 12)
-               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+       if (total_params < 12) {
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
 
        *mask = *directory = *resume_name = 0;
 
        srvstr_get_path(inbuf, resume_name, params+12, sizeof(resume_name), -1, STR_TERMINATE, &ntstatus, True);
        if (!NT_STATUS_IS_OK(ntstatus)) {
-               return ERROR_NT(ntstatus);
+               /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
+                  complain (it thinks we're asking for the directory above the shared
+                  path or an invalid name). Catch this as the resume name is only compared, never used in
+                  a file access. JRA. */
+               if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_OBJECT_PATH_SYNTAX_BAD)) {
+                       pstrcpy(resume_name, "..");
+               } else if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_OBJECT_NAME_INVALID)) {
+                       pstrcpy(resume_name, ".");
+               } else {
+                       return ERROR_NT(ntstatus);
+               }
        }
 
        DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
@@ -1596,8 +1869,9 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
        }
 
        switch (info_level) {
-               case SMB_INFO_STANDARD:
-               case SMB_INFO_QUERY_EA_SIZE:
+               case SMB_FIND_INFO_STANDARD:
+               case SMB_FIND_EA_SIZE:
+               case SMB_FIND_EA_LIST:
                case SMB_FIND_FILE_DIRECTORY_INFO:
                case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
                case SMB_FIND_FILE_NAMES_INFO:
@@ -1611,29 +1885,66 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
 
-       pdata = Realloc( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
-       if(pdata == NULL)
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       if (info_level == SMB_FIND_EA_LIST) {
+               uint32 ea_size;
+
+               if (total_data < 4) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               ea_size = IVAL(pdata,0);
+               if (ea_size != total_data) {
+                       DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
+total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+                                                                                                                                                     
+               if (!lp_ea_support(SNUM(conn))) {
+                       return ERROR_DOS(ERRDOS,ERReasnotsupported);
+               }
+                                                                                                                                                     
+               if ((ea_ctx = talloc_init("findnext_ea_list")) == NULL) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+
+               /* Pull out the list of names. */
+               ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
+               if (!ea_list) {
+                       talloc_destroy(ea_ctx);
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+       }
+
+       pdata = SMB_REALLOC( *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
+       if(pdata == NULL) {
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
 
        *ppdata = pdata;
        memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
 
        /* Realloc the params space */
-       params = Realloc(*pparams, 6*SIZEOFWORD);
-       if( params == NULL )
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       params = SMB_REALLOC(*pparams, 6*SIZEOFWORD);
+       if( params == NULL ) {
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
 
        *pparams = params;
 
        /* Check that the dptr is valid */
-       if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num)))
+       if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) {
+               talloc_destroy(ea_ctx);
                return ERROR_DOS(ERRDOS,ERRnofiles);
+       }
 
        string_set(&conn->dirpath,dptr_path(dptr_num));
 
        /* Get the wildcard mask from the dptr */
        if((p = dptr_wcard(dptr_num))== NULL) {
                DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
+               talloc_destroy(ea_ctx);
                return ERROR_DOS(ERRDOS,ERRnofiles);
        }
 
@@ -1643,10 +1954,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
        /* Get the attr mask from the dptr */
        dirtype = dptr_attr(dptr_num);
 
-       DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%d)\n",
+       DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
                dptr_num, mask, dirtype, 
                (long)conn->dirptr,
-               TellDir(conn->dirptr)));
+               dptr_TellDir(conn->dirptr)));
 
        /* We don't need to check for VOL here as this is returned by 
                a different TRANS2 call. */
@@ -1665,84 +1976,29 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
         */
 
        if(*resume_name && !continue_bit) {
+               SMB_STRUCT_STAT st;
 
+               long current_pos = 0;
                /*
-                * Fix for NT redirector problem triggered by resume key indexes
-                * changing between directory scans. We now return a resume key of 0
-                * and instead look for the filename to continue from (also given
-                * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
-                * findfirst/findnext (as is usual) then the directory pointer
-                * should already be at the correct place. Check this by scanning
-                * backwards looking for an exact (ie. case sensitive) filename match. 
-                * If we get to the beginning of the directory and haven't found it then scan
-                * forwards again looking for a match. JRA.
+                * Remember, mangle_map is called by
+                * get_lanman2_dir_entry(), so the resume name
+                * could be mangled. Ensure we check the unmangled name.
                 */
 
-               int current_pos, start_pos;
-               const char *dname = NULL;
-               pstring dname_pstring;
-               void *dirptr = conn->dirptr;
-               start_pos = TellDir(dirptr);
-               for(current_pos = start_pos; current_pos >= 0; current_pos--) {
-                       DEBUG(7,("call_trans2findnext: seeking to pos %d\n", current_pos));
-
-                       SeekDir(dirptr, current_pos);
-                       dname = ReadDirName(dirptr);
-                       if (dname) {
-                               /*
-                                * Remember, mangle_map is called by
-                                * get_lanman2_dir_entry(), so the resume name
-                                * could be mangled. Ensure we do the same
-                                * here.
-                                */
-                               
-                               /* make sure we get a copy that mangle_map can modify */
-
-                               pstrcpy(dname_pstring, dname);
-                               mangle_map( dname_pstring, False, True, SNUM(conn));
-                               
-                               if(strcsequal( resume_name, dname_pstring)) {
-                                       SeekDir(dirptr, current_pos+1);
-                                       DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
-                                       break;
-                               }
-                       }
+               if (mangle_is_mangled(resume_name)) {
+                       mangle_check_cache(resume_name, sizeof(resume_name)-1);
                }
 
                /*
-                * Scan forward from start if not found going backwards.
+                * Fix for NT redirector problem triggered by resume key indexes
+                * changing between directory scans. We now return a resume key of 0
+                * and instead look for the filename to continue from (also given
+                * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
+                * findfirst/findnext (as is usual) then the directory pointer
+                * should already be at the correct place.
                 */
-
-               if(current_pos < 0) {
-                       DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
-                       SeekDir(dirptr, start_pos);
-                       for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; ++current_pos) {
-
-                               /*
-                                * Remember, mangle_map is called by
-                                * get_lanman2_dir_entry(), so the resume name
-                                * could be mangled. Ensure we do the same
-                                * here.
-                                */
-
-                               if(dname) {
-                                       /* make sure we get a copy that mangle_map can modify */
-                                       
-                                       pstrcpy(dname_pstring, dname);
-                                       mangle_map(dname_pstring, False, True, SNUM(conn));
-
-                                       if(strcsequal( resume_name, dname_pstring)) {
-                                               SeekDir(dirptr, current_pos+1);
-                                               DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
-                                               break;
-                                       }
-                               }
-                       } /* end for */
-               } /* end if current_pos */
-               /* Can't find the name. Just resume from where we were... */
-               if (dname == 0) {
-                       SeekDir(dirptr, start_pos);
-               }
+
+               finished = !dptr_SearchDir(conn->dirptr, resume_name, &current_pos, &st);
        } /* end if resume_name && !continue_bit */
 
        for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
@@ -1759,7 +2015,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                                                mask,dirtype,info_level,
                                                requires_resume_key,dont_descend,
                                                &p,pdata,space_remaining, &out_of_space, &got_exact_match,
-                                               &last_name_off);
+                                               &last_entry_off, ea_list, ea_ctx);
                }
 
                if (finished && out_of_space)
@@ -1781,6 +2037,8 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
        }
   
+       talloc_destroy(ea_ctx);
+
        /* Check if we can close the dirptr */
        if(close_after_request || (finished && close_if_end)) {
                DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
@@ -1791,7 +2049,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
        SSVAL(params,0,numentries);
        SSVAL(params,2,finished);
        SSVAL(params,4,0); /* Never an EA error */
-       SSVAL(params,6,last_name_off);
+       SSVAL(params,6,last_entry_off);
 
        send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata));
 
@@ -1809,11 +2067,10 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
  Reply to a TRANS2_QFSINFO (query filesystem info).
 ****************************************************************************/
 
-static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, 
-                       int length, int bufsize,
-                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
-       int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *pdata = *ppdata;
        char *params = *pparams;
        uint16 info_level = SVAL(params,0);
@@ -1831,9 +2088,10 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
                return ERROR_DOS(ERRSRV,ERRinvdevice);
        }
 
-       pdata = Realloc(*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
-       if ( pdata == NULL )
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       pdata = SMB_REALLOC(*ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
+       if ( pdata == NULL ) {
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
 
        *ppdata = pdata;
        memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
@@ -1843,7 +2101,10 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
                {
                        SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 18;
-                       SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); 
+                       if (SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+                               return(UNIXERROR(ERRHRD,ERRgeneral));
+                       }
+
                        block_size = lp_block_size(snum);
                        if (bsize < block_size) {
                                SMB_BIG_UINT factor = block_size/bsize;
@@ -1878,8 +2139,14 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsi
                         * Add volume serial number - hash of a combination of
                         * the called hostname and the service name.
                         */
-                       SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(local_machine)<<16) );
-                       len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_NOALIGN);
+                       SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
+                       /*
+                        * Win2k3 and previous mess this up by sending a name length
+                        * one byte short. I believe only older clients (OS/2 Win9x) use
+                        * this call so try fixing this by adding a terminating null to
+                        * the pushed string. The change here was adding the STR_TERMINATE. JRA.
+                        */
+                       len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, -1, STR_NOALIGN|STR_TERMINATE);
                        SCVAL(pdata,l2_vol_cch,len);
                        data_len = l2_vol_szVolLabel + len;
                        DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
@@ -1921,7 +2188,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsi
                         * the called hostname and the service name.
                         */
                        SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ 
-                               (str_checksum(local_machine)<<16));
+                               (str_checksum(get_local_machine_name())<<16));
 
                        len = srvstr_push(outbuf, pdata+18, vname, -1, STR_UNICODE);
                        SIVAL(pdata,12,len);
@@ -1935,7 +2202,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsi
                {
                        SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 24;
-                       SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize);
+                       if (SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+                               return(UNIXERROR(ERRHRD,ERRgeneral));
+                       }
                        block_size = lp_block_size(snum);
                        if (bsize < block_size) {
                                SMB_BIG_UINT factor = block_size/bsize;
@@ -1965,7 +2234,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                {
                        SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
                        data_len = 32;
-                       SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize);
+                       if (SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
+                               return(UNIXERROR(ERRHRD,ERRgeneral));
+                       }
                        block_size = lp_block_size(snum);
                        if (bsize < block_size) {
                                SMB_BIG_UINT factor = block_size/bsize;
@@ -2086,7 +2357,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        data_len = 12;
                        SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
                        SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
-                       SBIG_UINT(pdata,4,((SMB_BIG_UINT)0)); /* No capabilities for now... */
+                       SBIG_UINT(pdata,4,((SMB_BIG_UINT)CIFS_UNIX_POSIX_ACLS_CAP)); /* We have POSIX ACLs. */
                        break;
 
                case SMB_MAC_QUERY_FS_INFO:
@@ -2117,9 +2388,9 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
  Reply to a TRANS2_SETFSINFO (set filesystem info).
 ****************************************************************************/
 
-static int call_trans2setfsinfo(connection_struct *conn,
-                               char *inbuf, char *outbuf, int length, int bufsize,
-                               char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *pdata = *ppdata;
        char *params = *pparams;
@@ -2143,7 +2414,7 @@ static int call_trans2setfsinfo(connection_struct *conn,
        if (total_params < 4) {
                DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
                        total_params));
-               return ERROR_DOS(ERRDOS,ERRinvalidparam);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
        }
 
        fsp = file_fsp(params,0);
@@ -2227,8 +2498,8 @@ static int call_trans2setfsinfo(connection_struct *conn,
 #endif /* HAVE_SYS_QUOTAS */
 
 /****************************************************************************
*  Utility function to set bad path error.
- ****************************************************************************/
+ Utility function to set bad path error.
+****************************************************************************/
 
 int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint32 def_code)
 {
@@ -2245,17 +2516,132 @@ int set_bad_path_error(int err, BOOL bad_path, char *outbuf, int def_class, uint
        return UNIXERROR(def_class,def_code);
 }
 
+#if defined(HAVE_POSIX_ACLS)
+/****************************************************************************
+ Utility function to count the number of entries in a POSIX acl.
+****************************************************************************/
+
+static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
+{
+       unsigned int ace_count = 0;
+       int entry_id = SMB_ACL_FIRST_ENTRY;
+       SMB_ACL_ENTRY_T entry;
+
+       while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+               /* get_next... */
+               if (entry_id == SMB_ACL_FIRST_ENTRY) {
+                       entry_id = SMB_ACL_NEXT_ENTRY;
+               }
+               ace_count++;
+       }
+       return ace_count;
+}
+
+/****************************************************************************
+ Utility function to marshall a POSIX acl into wire format.
+****************************************************************************/
+
+static BOOL marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
+{
+       int entry_id = SMB_ACL_FIRST_ENTRY;
+       SMB_ACL_ENTRY_T entry;
+
+       while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
+               SMB_ACL_TAG_T tagtype;
+               SMB_ACL_PERMSET_T permset;
+               unsigned char perms = 0;
+               unsigned int own_grp;
+
+               /* get_next... */
+               if (entry_id == SMB_ACL_FIRST_ENTRY) {
+                       entry_id = SMB_ACL_NEXT_ENTRY;
+               }
+
+               if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
+                       DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
+                       return False;
+               }
+
+               if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
+                       DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
+                       return False;
+               }
+
+               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
+               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
+               perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
+
+               SCVAL(pdata,1,perms);
+
+               switch (tagtype) {
+                       case SMB_ACL_USER_OBJ:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
+                               own_grp = (unsigned int)pst->st_uid;
+                               SIVAL(pdata,2,own_grp);
+                               SIVAL(pdata,6,0);
+                               break;
+                       case SMB_ACL_USER:
+                               {
+                                       uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       if (!puid) {
+                                               DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+                                       }
+                                       own_grp = (unsigned int)*puid;
+                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
+                                       SCVAL(pdata,0,SMB_POSIX_ACL_USER);
+                                       SIVAL(pdata,2,own_grp);
+                                       SIVAL(pdata,6,0);
+                                       break;
+                               }
+                       case SMB_ACL_GROUP_OBJ:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
+                               own_grp = (unsigned int)pst->st_gid;
+                               SIVAL(pdata,2,own_grp);
+                               SIVAL(pdata,6,0);
+                               break;
+                       case SMB_ACL_GROUP:
+                               {
+                                       gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
+                                       if (!pgid) {
+                                               DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
+                                       }
+                                       own_grp = (unsigned int)*pgid;
+                                       SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
+                                       SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
+                                       SIVAL(pdata,2,own_grp);
+                                       SIVAL(pdata,6,0);
+                                       break;
+                               }
+                       case SMB_ACL_MASK:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
+                               SIVAL(pdata,2,0xFFFFFFFF);
+                               SIVAL(pdata,6,0xFFFFFFFF);
+                               break;
+                       case SMB_ACL_OTHER:
+                               SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
+                               SIVAL(pdata,2,0xFFFFFFFF);
+                               SIVAL(pdata,6,0xFFFFFFFF);
+                               break;
+                       default:
+                               DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
+                               return False;
+               }
+               pdata += SMB_POSIX_ACL_ENTRY_SIZE;
+       }
+
+       return True;
+}
+#endif
+
 /****************************************************************************
  Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
  file name or file id).
 ****************************************************************************/
 
-static int call_trans2qfilepathinfo(connection_struct *conn,
-                                   char *inbuf, char *outbuf, int length, 
-                                   int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
-       int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
        char *params = *pparams;
        char *pdata = *ppdata;
        uint16 tran_call = SVAL(inbuf, smb_setup0);
@@ -2263,7 +2649,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        int mode=0;
        SMB_OFF_T file_size=0;
        SMB_BIG_UINT allocation_size=0;
-       unsigned int data_size;
+       unsigned int data_size = 0;
        unsigned int param_size = 2;
        SMB_STRUCT_STAT sbuf;
        pstring fname, dos_fname;
@@ -2276,6 +2662,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        int len;
        time_t c_time;
        files_struct *fsp = NULL;
+       TALLOC_CTX *ea_ctx = NULL;
+       struct ea_list *ea_list = NULL;
        uint32 desired_access = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
 
        if (!params)
@@ -2284,8 +2672,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        ZERO_STRUCT(sbuf);
 
        if (tran_call == TRANSACT2_QFILEINFO) {
-               if (total_params < 4)
-                       return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+               if (total_params < 4) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
 
                fsp = file_fsp(params,0);
                info_level = SVAL(params,2);
@@ -2340,8 +2729,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                NTSTATUS status = NT_STATUS_OK;
 
                /* qpathinfo */
-               if (total_params < 6)
-                       return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+               if (total_params < 6) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
 
                info_level = SVAL(params,0);
 
@@ -2393,31 +2783,78 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
        fullpathname = fname;
        file_size = get_file_size(sbuf);
-       allocation_size = get_allocation_size(fsp,&sbuf);
-       if (mode & aDIR)
+       allocation_size = get_allocation_size(conn,fsp,&sbuf);
+       if (mode & aDIR) {
+               /* This is necessary, as otherwise the desktop.ini file in
+                * this folder is ignored */
+               mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
                file_size = 0;
+       }
+
+       /* Pull any EA list from the data portion. */
+       if (info_level == SMB_INFO_QUERY_EAS_FROM_LIST) {
+               uint32 ea_size;
+
+               if (total_data < 4) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+               ea_size = IVAL(pdata,0);
+
+               if (total_data > 0 && ea_size != total_data) {
+                       DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
+total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
 
-       params = Realloc(*pparams,2);
-       if (params == NULL)
-         return ERROR_DOS(ERRDOS,ERRnomem);
+               if (!lp_ea_support(SNUM(conn))) {
+                       return ERROR_DOS(ERRDOS,ERReasnotsupported);
+               }
+
+               if ((ea_ctx = talloc_init("ea_list")) == NULL) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+
+               /* Pull out the list of names. */
+               ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
+               if (!ea_list) {
+                       talloc_destroy(ea_ctx);
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+       }
+
+       params = SMB_REALLOC(*pparams,2);
+       if (params == NULL) {
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
        memset((char *)params,'\0',2);
        data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
-       pdata = Realloc(*ppdata, data_size); 
-       if ( pdata == NULL )
-               return ERROR_DOS(ERRDOS,ERRnomem);
-       *ppdata = pdata;
-
-       if (total_data > 0 && IVAL(pdata,0) == total_data) {
-               /* uggh, EAs for OS2 */
-               DEBUG(4,("Rejecting EA request with total_data=%d\n",total_data));
-               return ERROR_DOS(ERRDOS,ERReasnotsupported);
+       pdata = SMB_REALLOC(*ppdata, data_size); 
+       if ( pdata == NULL ) {
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
+       *ppdata = pdata;
 
        memset((char *)pdata,'\0',data_size);
 
        c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
 
+       if (fsp) {
+               if (fsp->pending_modtime) {
+                       /* the pending modtime overrides the current modtime */
+                       sbuf.st_mtime = fsp->pending_modtime;
+               }
+       } else {
+               /* Do we have this path open ? */
+               files_struct *fsp1 = file_find_di_first(sbuf.st_dev, sbuf.st_ino);
+               if (fsp1 && fsp1->pending_modtime) {
+                       /* the pending modtime overrides the current modtime */
+                       sbuf.st_mtime = fsp1->pending_modtime;
+               }
+       }
+
        if (lp_dos_filetime_resolution(SNUM(conn))) {
                c_time &= ~1;
                sbuf.st_atime &= ~1;
@@ -2472,21 +2909,51 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        break;
                        
                case SMB_INFO_QUERY_EAS_FROM_LIST:
+               {
+                       size_t total_ea_len = 0;
+                       struct ea_list *ea_file_list = NULL;
+
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
-                       data_size = 24;
-                       put_dos_date2(pdata,0,c_time);
-                       put_dos_date2(pdata,4,sbuf.st_atime);
-                       put_dos_date2(pdata,8,sbuf.st_mtime);
-                       SIVAL(pdata,12,(uint32)file_size);
-                       SIVAL(pdata,16,(uint32)allocation_size);
-                       SIVAL(pdata,20,mode);
+
+                       ea_file_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+                       ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
+
+                       if (!ea_list || (total_ea_len > data_size)) {
+                               talloc_destroy(ea_ctx);
+                               data_size = 4;
+                               SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
+                               break;
+                       }
+
+                       data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
+                       talloc_destroy(ea_ctx);
                        break;
+               }
 
                case SMB_INFO_QUERY_ALL_EAS:
-                       DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
+               {
                        /* We have data_size bytes to put EA's into. */
-                       data_size = fill_ea_buffer(pdata, data_size, conn, fsp, fname);
+                       size_t total_ea_len = 0;
+
+                       DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
+
+                       ea_ctx = talloc_init("ea_ctx");
+                       if (!ea_ctx) {
+                               return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       }
+
+                       ea_list = get_ea_list_from_file(ea_ctx, conn, fsp, fname, &total_ea_len);
+                       if (!ea_list || (total_ea_len > data_size)) {
+                               talloc_destroy(ea_ctx);
+                               data_size = 4;
+                               SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
+                               break;
+                       }
+
+                       data_size = fill_ea_buffer(ea_ctx, pdata, data_size, conn, ea_list);
+                       talloc_destroy(ea_ctx);
                        break;
+               }
 
                case SMB_FILE_BASIC_INFORMATION:
                case SMB_QUERY_FILE_BASIC_INFO:
@@ -2730,7 +3197,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        SOFF_T(pdata,0,get_file_size(sbuf));             /* File size 64 Bit */
                        pdata += 8;
 
-                       SOFF_T(pdata,0,get_allocation_size(fsp,&sbuf)); /* Number of bytes used on disk - 64 Bit */
+                       SOFF_T(pdata,0,get_allocation_size(conn,fsp,&sbuf)); /* Number of bytes used on disk - 64 Bit */
                        pdata += 8;
 
                        put_long_date(pdata,sbuf.st_ctime);       /* Creation Time 64 Bit */
@@ -2802,6 +3269,85 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                break;
                        }
 
+#if defined(HAVE_POSIX_ACLS)
+               case SMB_QUERY_POSIX_ACL:
+                       {
+                               SMB_ACL_T file_acl = NULL;
+                               SMB_ACL_T def_acl = NULL;
+                               uint16 num_file_acls = 0;
+                               uint16 num_def_acls = 0;
+
+                               if (fsp && !fsp->is_directory && (fsp->fd != -1)) {
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
+                               } else {
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+                               }
+
+                               if (file_acl == NULL && no_acl_syscall_error(errno)) {
+                                       DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n",
+                                               fname ));
+                                       return ERROR_NT(NT_STATUS_NOT_IMPLEMENTED);
+                               }
+
+                               if (S_ISDIR(sbuf.st_mode)) {
+                                       if (fsp && fsp->is_directory) {
+                                               def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
+                                       } else {
+                                               def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT);
+                                       }
+                                       def_acl = free_empty_sys_acl(conn, def_acl);
+                               }
+
+                               num_file_acls = count_acl_entries(conn, file_acl);
+                               num_def_acls = count_acl_entries(conn, def_acl);
+
+                               if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
+                                       DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n",
+                                               data_size,
+                                               (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
+                                                       SMB_POSIX_ACL_HEADER_SIZE) ));
+                                       if (file_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                       }
+                                       if (def_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                       }
+                                       return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL);
+                               }
+
+                               SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
+                               SSVAL(pdata,2,num_file_acls);
+                               SSVAL(pdata,4,num_def_acls);
+                               if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, &sbuf, file_acl)) {
+                                       if (file_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                       }
+                                       if (def_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                       }
+                                       return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+                               }
+                               if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) {
+                                       if (file_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                                       }
+                                       if (def_acl) {
+                                               SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                                       }
+                                       return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
+                               }
+
+                               if (file_acl) {
+                                       SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
+                               }
+                               if (def_acl) {
+                                       SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
+                               }
+                               data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
+                               break;
+                       }
+#endif
+
                default:
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
@@ -2824,10 +3370,12 @@ NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close, u
                 * Only allow delete on close for writable files.
                 */
 
-               if (dosmode & aRONLY) {
-                       DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but file attribute is readonly.\n",
-                               fsp->fsp_name ));
-                       return NT_STATUS_CANNOT_DELETE;
+               if (!lp_delete_readonly(SNUM(fsp->conn))) {
+                       if (dosmode & aRONLY) {
+                               DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but file attribute is readonly.\n",
+                                       fsp->fsp_name ));
+                               return NT_STATUS_CANNOT_DELETE;
+                       }
                }
 
                /*
@@ -2983,9 +3531,9 @@ NTSTATUS hardlink_internals(connection_struct *conn, char *oldname, char *newnam
  Reply to a TRANS2_SETFILEINFO (set file info by fileid).
 ****************************************************************************/
 
-static int call_trans2setfilepathinfo(connection_struct *conn,
-                                       char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
        char *pdata = *ppdata;
@@ -3010,8 +3558,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        ZERO_STRUCT(sbuf);
 
        if (tran_call == TRANSACT2_SETFILEINFO) {
-               if (total_params < 4)
-                       return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+               if (total_params < 4) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
 
                fsp = file_fsp(params,0);
                info_level = SVAL(params,2);    
@@ -3057,8 +3606,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                }
        } else {
                /* set path info */
-               if (total_params < 6)
-                       return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+               if (total_params < 6) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
 
                info_level = SVAL(params,0);    
                srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), -1, STR_TERMINATE, &status, False);
@@ -3097,15 +3647,16 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n",
                tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data));
 
-       /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,2);
-       if(params == NULL)
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       /* Realloc the parameter size */
+       params = SMB_REALLOC(*pparams,2);
+       if(params == NULL) {
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
 
        SSVAL(params,0,0);
 
-       if (fsp) {
+       if (fsp && fsp->pending_modtime) {
                /* the pending modtime overrides the current modtime */
                sbuf.st_mtime = fsp->pending_modtime;
        }
@@ -3122,8 +3673,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        switch (info_level) {
                case SMB_INFO_STANDARD:
                {
-                       if (total_data < 12)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 12) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        /* access time */
                        tvs.actime = make_unix_date2(pdata+l1_fdateLastAccess);
@@ -3133,17 +3685,46 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                }
 
                case SMB_INFO_SET_EA:
-                       status = set_ea(conn, fsp, fname, pdata, total_data);
-                       if (NT_STATUS_V(status) !=  NT_STATUS_V(NT_STATUS_OK))
+               {
+                       struct ea_list *ea_list = NULL;
+                       TALLOC_CTX *ctx = NULL;
+
+                       if (total_data < 10) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       if (IVAL(pdata,0) > total_data) {
+                               DEBUG(10,("call_trans2setfilepathinfo: bad total data size (%u) > %u\n",
+                                       IVAL(pdata,0), (unsigned int)total_data));
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       ctx = talloc_init("SMB_INFO_SET_EA");
+                       if (!ctx) {
+                               return ERROR_NT(NT_STATUS_NO_MEMORY);
+                       }
+                       ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
+                       if (!ea_list) {
+                               talloc_destroy(ctx);
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       status = set_ea(conn, fsp, fname, ea_list);
+                       talloc_destroy(ctx);
+
+                       if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
+                       }
                        break;
+               }
 
+#if 0
+               /* The following 2 info levels are only valid on query, not set. Remove them. JRA. */
                /* XXXX um, i don't think this is right.
                        it's also not in the cifs6.txt spec.
                */
                case SMB_INFO_QUERY_EAS_FROM_LIST:
                        if (total_data < 28)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
                        tvs.actime = make_unix_date2(pdata+8);
                        tvs.modtime = make_unix_date2(pdata+12);
@@ -3154,13 +3735,14 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                /* XXXX nor this.  not in cifs6.txt, either. */
                case SMB_INFO_QUERY_ALL_EAS:
                        if (total_data < 28)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
                        tvs.actime = make_unix_date2(pdata+8);
                        tvs.modtime = make_unix_date2(pdata+12);
                        size = IVAL(pdata,16);
                        dosmode = IVAL(pdata,24);
                        break;
+#endif
 
                case SMB_SET_FILE_BASIC_INFO:
                case SMB_FILE_BASIC_INFORMATION:
@@ -3169,8 +3751,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        time_t write_time;
                        time_t changed_time;
 
-                       if (total_data < 36)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 36) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        /* Ignore create time at offset pdata. */
 
@@ -3182,13 +3765,13 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
 
                        tvs.modtime = MIN(write_time, changed_time);
 
-                       if (write_time > tvs.modtime && write_time != 0xffffffff) {
+                       if (write_time > tvs.modtime && write_time != (time_t)-1) {
                                tvs.modtime = write_time;
                        }
                        /* Prefer a defined time to an undefined one. */
-                       if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
-                               tvs.modtime = (write_time == (time_t)0 || write_time == (time_t)-1
-                                       ? changed_time : write_time);
+                       if (null_mtime(tvs.modtime)) {
+                               tvs.modtime = null_mtime(write_time) ? changed_time : write_time;
+                       }
 
                        /* attributes */
                        dosmode = IVAL(pdata,32);
@@ -3201,8 +3784,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        int ret = -1;
                        SMB_BIG_UINT allocation_size;
 
-                       if (total_data < 8)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 8) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        allocation_size = (SMB_BIG_UINT)IVAL(pdata,0);
 #ifdef LARGE_SMB_OFF_T
@@ -3214,8 +3798,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
                                        fname, (double)allocation_size ));
 
-                       if (allocation_size)
-                               allocation_size = smb_roundup(allocation_size);
+                       if (allocation_size) {
+                               allocation_size = smb_roundup(conn, allocation_size);
+                       }
 
                        if(allocation_size != get_file_size(sbuf)) {
                                SMB_STRUCT_STAT new_sbuf;
@@ -3274,8 +3859,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                case SMB_FILE_END_OF_FILE_INFORMATION:
                case SMB_SET_FILE_END_OF_FILE_INFO:
                {
-                       if (total_data < 8)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 8) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        size = IVAL(pdata,0);
 #ifdef LARGE_SMB_OFF_T
@@ -3293,8 +3879,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                {
                        BOOL delete_on_close;
 
-                       if (total_data < 1)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 1) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        delete_on_close = (CVAL(pdata,0) ? True : False);
 
@@ -3307,13 +3894,15 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
 
                        status = set_delete_on_close_internal(fsp, delete_on_close, dosmode);
  
-                       if (NT_STATUS_V(status) !=  NT_STATUS_V(NT_STATUS_OK))
+                       if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
+                       }
 
                        /* The set is across all open files on this dev/inode pair. */
                        status =set_delete_on_close_over_all(fsp, delete_on_close);
-                       if (NT_STATUS_V(status) !=  NT_STATUS_V(NT_STATUS_OK))
+                       if (!NT_STATUS_IS_OK(status)) {
                                return ERROR_NT(status);
+                       }
 
                        break;
                }
@@ -3322,8 +3911,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                {
                        SMB_BIG_UINT position_information;
 
-                       if (total_data < 8)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 8) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        position_information = (SMB_BIG_UINT)IVAL(pdata,0);
 #ifdef LARGE_SMB_OFF_T
@@ -3339,6 +3929,26 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        break;
                }
 
+               /* From tridge Samba4 : 
+                * MODE_INFORMATION in setfileinfo (I have no
+                * idea what "mode information" on a file is - it takes a value of 0,
+                * 2, 4 or 6. What could it be?).
+                */
+
+               case SMB_FILE_MODE_INFORMATION:
+               {
+                       uint32 mode;
+
+                       if (total_data < 4) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       mode = IVAL(pdata,0);
+                       if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       break;
+               }
+
                /*
                 * CIFS UNIX extensions.
                 */
@@ -3347,8 +3957,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                {
                        uint32 raw_unixmode;
 
-                       if (total_data < 100)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 100) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
                           IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
@@ -3361,8 +3972,8 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
 #endif /* LARGE_SMB_OFF_T */
                        }
                        pdata+=24;          /* ctime & st_blocks are not changed */
-                       tvs.actime = interpret_long_unix_date(pdata); /* access_time */
-                       tvs.modtime = interpret_long_unix_date(pdata+8); /* modification_time */
+                       tvs.actime = interpret_long_date(pdata); /* access_time */
+                       tvs.modtime = interpret_long_date(pdata+8); /* modification_time */
                        pdata+=16;
                        set_owner = (uid_t)IVAL(pdata,0);
                        pdata += 8;
@@ -3397,8 +4008,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                                if (tran_call == TRANSACT2_SETFILEINFO)
                                        return(ERROR_DOS(ERRDOS,ERRnoaccess));
 
-                               if (raw_unixmode == SMB_MODE_NO_CHANGE)
-                                       return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                               if (raw_unixmode == SMB_MODE_NO_CHANGE) {
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                               }
 
 #if defined(HAVE_MAKEDEV)
                                dev = makedev(dev_major, dev_minor);
@@ -3566,8 +4178,9 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        pstring base_name;
                        char *p;
 
-                       if (total_data < 12)
-                               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+                       if (total_data < 12) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
 
                        overwrite = (CVAL(pdata,0) ? True : False);
                        root_fid = IVAL(pdata,4);
@@ -3609,16 +4222,71 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
                        return(-1);
                }
+
+#if defined(HAVE_POSIX_ACLS)
+               case SMB_SET_POSIX_ACL:
+               {
+                       uint16 posix_acl_version;
+                       uint16 num_file_acls;
+                       uint16 num_def_acls;
+                       BOOL valid_file_acls = True;
+                       BOOL valid_def_acls = True;
+
+                       if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+                       posix_acl_version = SVAL(pdata,0);
+                       num_file_acls = SVAL(pdata,2);
+                       num_def_acls = SVAL(pdata,4);
+
+                       if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+                               valid_file_acls = False;
+                               num_file_acls = 0;
+                       }
+
+                       if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
+                               valid_def_acls = False;
+                               num_def_acls = 0;
+                       }
+
+                       if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
+                                       (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
+                               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                       }
+
+                       if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls,
+                                       pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
+                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       }
+
+                       if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, &sbuf, num_def_acls,
+                                       pdata + SMB_POSIX_ACL_HEADER_SIZE +
+                                       (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
+                               return(UNIXERROR(ERRDOS,ERRnoaccess));
+                       }
+
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
+               }
+#endif
+
                default:
                        return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
 
        /* get some defaults (no modifications) if any info is zero or -1. */
-       if (tvs.actime == (time_t)0 || tvs.actime == (time_t)-1)
+       if (null_mtime(tvs.actime)) {
                tvs.actime = sbuf.st_atime;
+       }
 
-       if (tvs.modtime == (time_t)0 || tvs.modtime == (time_t)-1)
+       if (null_mtime(tvs.modtime)) {
                tvs.modtime = sbuf.st_mtime;
+       }
 
        DEBUG(6,("actime: %s " , ctime(&tvs.actime)));
        DEBUG(6,("modtime: %s ", ctime(&tvs.modtime)));
@@ -3650,41 +4318,19 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
         * Try and set the times, size and mode of this file -
         * if they are different from the current values
         */
-       if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) {
-               if(fsp != NULL) {
-                       /*
-                        * This was a setfileinfo on an open file.
-                        * NT does this a lot. It's actually pointless
-                        * setting the time here, as it will be overwritten
-                        * on the next write, so we save the request
-                        * away and will set it on file close. JRA.
-                        */
-
-                       if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
-                               DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", ctime(&tvs.modtime) ));
-                               fsp->pending_modtime = tvs.modtime;
-                       }
-
-               } else {
-
-                       DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
-
-                       if(file_utime(conn, fname, &tvs)!=0)
-                               return(UNIXERROR(ERRDOS,ERRnoaccess));
-               }
-       }
 
        /* check the mode isn't different, before changing it */
        if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, &sbuf))) {
 
                DEBUG(10,("call_trans2setfilepathinfo: file %s : setting dos mode %x\n", fname, dosmode ));
 
-               if(file_set_dosmode(conn, fname, dosmode, NULL)) {
+               if(file_set_dosmode(conn, fname, dosmode, &sbuf, False)) {
                        DEBUG(2,("file_set_dosmode of %s failed (%s)\n", fname, strerror(errno)));
                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                }
        }
 
+       /* Now the size. */
        if (size != get_file_size(sbuf)) {
 
                int ret;
@@ -3725,6 +4371,34 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        return (UNIXERROR(ERRHRD,ERRdiskfull));
        }
 
+       /*
+        * Finally the times.
+        */
+       if (sbuf.st_mtime != tvs.modtime || sbuf.st_atime != tvs.actime) {
+               if(fsp != NULL) {
+                       /*
+                        * This was a setfileinfo on an open file.
+                        * NT does this a lot. We also need to 
+                        * set the time here, as it can be read by 
+                        * FindFirst/FindNext and with the patch for bug #2045
+                        * in smbd/fileio.c it ensures that this timestamp is
+                        * kept sticky even after a write. We save the request
+                        * away and will set it on file close and after a write. JRA.
+                        */
+
+                       if (tvs.modtime != (time_t)0 && tvs.modtime != (time_t)-1) {
+                               DEBUG(10,("call_trans2setfilepathinfo: setting pending modtime to %s\n", ctime(&tvs.modtime) ));
+                               fsp_set_pending_modtime(fsp, tvs.modtime);
+                       }
+
+               }
+               DEBUG(10,("call_trans2setfilepathinfo: setting utimes to modified values.\n"));
+
+               if(file_utime(conn, fname, &tvs)!=0) {
+                       return(UNIXERROR(ERRDOS,ERRnoaccess));
+               }
+       }
+
        SSVAL(params,0,0);
        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
   
@@ -3735,22 +4409,26 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
  Reply to a TRANS2_MKDIR (make directory with extended attributes).
 ****************************************************************************/
 
-static int call_trans2mkdir(connection_struct *conn,
-                           char *inbuf, char *outbuf, int length, int bufsize,
-                               char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
+       char *pdata = *ppdata;
        pstring directory;
        int ret = -1;
        SMB_STRUCT_STAT sbuf;
        BOOL bad_path = False;
        NTSTATUS status = NT_STATUS_OK;
+       TALLOC_CTX *ctx = NULL;
+       struct ea_list *ea_list = NULL;
 
        if (!CAN_WRITE(conn))
                return ERROR_DOS(ERRSRV,ERRaccess);
 
-       if (total_params < 4)
-               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+       if (total_params < 4) {
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
 
        srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
@@ -3763,18 +4441,58 @@ static int call_trans2mkdir(connection_struct *conn,
        if (bad_path) {
                return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
        }
-       if (check_name(directory,conn))
-               ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
+
+       /* Any data in this call is an EA list. */
+       if (total_data && !lp_ea_support(SNUM(conn))) {
+               return ERROR_NT(NT_STATUS_EAS_NOT_SUPPORTED);
+       }
+
+       if (total_data) {
+               if (total_data < 10) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               if (IVAL(pdata,0) > total_data) {
+                       DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
+                               IVAL(pdata,0), (unsigned int)total_data));
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               ctx = talloc_init("TRANS2_MKDIR_SET_EA");
+               if (!ctx) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+               ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
+               if (!ea_list) {
+                       talloc_destroy(ctx);
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+       }
+
+       if (check_name(directory,conn)) {
+               ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory,True));
+       }
   
        if(ret < 0) {
+               talloc_destroy(ctx);
                DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
+       /* Try and set any given EA. */
+       if (total_data) {
+               status = set_ea(conn, NULL, directory, ea_list);
+               talloc_destroy(ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return ERROR_NT(status);
+               }
+       }
+
        /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,2);
-       if(params == NULL)
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       params = SMB_REALLOC(*pparams,2);
+       if(params == NULL) {
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
 
        SSVAL(params,0,0);
@@ -3789,16 +4507,17 @@ static int call_trans2mkdir(connection_struct *conn,
  We don't actually do this - we just send a null response.
 ****************************************************************************/
 
-static int call_trans2findnotifyfirst(connection_struct *conn,
-                                       char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        static uint16 fnf_handle = 257;
        char *params = *pparams;
        uint16 info_level;
 
-       if (total_params < 6)
-               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+       if (total_params < 6) {
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
 
        info_level = SVAL(params,4);
        DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
@@ -3812,9 +4531,10 @@ static int call_trans2findnotifyfirst(connection_struct *conn,
        }
 
        /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,6);
-       if(params == NULL) 
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       params = SMB_REALLOC(*pparams,6);
+       if(params == NULL) {
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
 
        SSVAL(params,0,fnf_handle);
@@ -3836,18 +4556,19 @@ static int call_trans2findnotifyfirst(connection_struct *conn,
  changes). Currently this does nothing.
 ****************************************************************************/
 
-static int call_trans2findnotifynext(connection_struct *conn,
-                                       char *inbuf, char *outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2findnotifynext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
 
        DEBUG(3,("call_trans2findnotifynext\n"));
 
        /* Realloc the parameter and data sizes */
-       params = Realloc(*pparams,4);
-       if(params == NULL)
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       params = SMB_REALLOC(*pparams,4);
+       if(params == NULL) {
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
 
        SSVAL(params,0,0); /* No changes */
@@ -3862,9 +4583,9 @@ static int call_trans2findnotifynext(connection_struct *conn,
  Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
 ****************************************************************************/
 
-static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
-                                       char* outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
        pstring pathname;
@@ -3873,8 +4594,9 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
 
        DEBUG(10,("call_trans2getdfsreferral\n"));
 
-       if (total_params < 2)
-               return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+       if (total_params < 2) {
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+       }
 
        max_referral_level = SVAL(params,0);
 
@@ -3898,9 +4620,9 @@ static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf,
  Reply to a TRANS2_IOCTL - used for OS/2 printing.
 ****************************************************************************/
 
-static int call_trans2ioctl(connection_struct *conn, char* inbuf,
-                                       char* outbuf, int length, int bufsize,
-                                       char **pparams, int total_params, char **ppdata, int total_data)
+static int call_trans2ioctl(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *pdata = *ppdata;
        files_struct *fsp = file_fsp(inbuf,smb_vwv15);
@@ -3912,9 +4634,10 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf,
 
        if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
                        (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
-               pdata = Realloc(*ppdata, 32);
-               if(pdata == NULL)
-                       return ERROR_DOS(ERRDOS,ERRnomem);
+               pdata = SMB_REALLOC(*ppdata, 32);
+               if(pdata == NULL) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
                *ppdata = pdata;
 
                /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
@@ -4004,9 +4727,9 @@ int reply_trans2(connection_struct *conn,
        int outsize = 0;
        unsigned int total_params = SVAL(inbuf, smb_tpscnt);
        unsigned int total_data =SVAL(inbuf, smb_tdscnt);
+       unsigned int max_data_bytes = SVAL(inbuf, smb_mdrcnt);
 #if 0
        unsigned int max_param_reply = SVAL(inbuf, smb_mprcnt);
-       unsigned int max_data_reply = SVAL(inbuf, smb_mdrcnt);
        unsigned int max_setup_fields = SVAL(inbuf, smb_msrcnt);
        BOOL close_tid = BITSETW(inbuf+smb_flags,0);
        BOOL no_final_response = BITSETW(inbuf+smb_flags,1);
@@ -4057,22 +4780,22 @@ int reply_trans2(connection_struct *conn,
                        DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt));
                        DEBUG(2,("Transaction is %d\n",tran_call));
                        END_PROFILE(SMBtrans2);
-                       ERROR_DOS(ERRDOS,ERRinvalidparam);
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
                }
        }
     
        /* Allocate the space for the maximum needed parameters and data */
        if (total_params > 0)
-               params = (char *)malloc(total_params);
+               params = (char *)SMB_MALLOC(total_params);
        if (total_data > 0)
-               data = (char *)malloc(total_data);
+               data = (char *)SMB_MALLOC(total_data);
   
        if ((total_params && !params)  || (total_data && !data)) {
                DEBUG(2,("Out of memory in reply_trans2\n"));
                SAFE_FREE(params);
                SAFE_FREE(data); 
                END_PROFILE(SMBtrans2);
-               return ERROR_DOS(ERRDOS,ERRnomem);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
 
        /* Copy the param and data bytes sent with this request into
@@ -4204,28 +4927,28 @@ int reply_trans2(connection_struct *conn,
        case TRANSACT2_OPEN:
                START_PROFILE_NESTED(Trans2_open);
                outsize = call_trans2open(conn, inbuf, outbuf, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_open);
                break;
 
        case TRANSACT2_FINDFIRST:
                START_PROFILE_NESTED(Trans2_findfirst);
                outsize = call_trans2findfirst(conn, inbuf, outbuf, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findfirst);
                break;
 
        case TRANSACT2_FINDNEXT:
                START_PROFILE_NESTED(Trans2_findnext);
                outsize = call_trans2findnext(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findnext);
                break;
 
        case TRANSACT2_QFSINFO:
                START_PROFILE_NESTED(Trans2_qfsinfo);
                outsize = call_trans2qfsinfo(conn, inbuf, outbuf, length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_qfsinfo);
            break;
 
@@ -4233,7 +4956,7 @@ int reply_trans2(connection_struct *conn,
        case TRANSACT2_SETFSINFO:
                START_PROFILE_NESTED(Trans2_setfsinfo);
                outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_setfsinfo);
                break;
 #endif
@@ -4241,47 +4964,47 @@ int reply_trans2(connection_struct *conn,
        case TRANSACT2_QFILEINFO:
                START_PROFILE_NESTED(Trans2_qpathinfo);
                outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_qpathinfo);
                break;
        case TRANSACT2_SETPATHINFO:
        case TRANSACT2_SETFILEINFO:
                START_PROFILE_NESTED(Trans2_setpathinfo);
                outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_setpathinfo);
                break;
 
        case TRANSACT2_FINDNOTIFYFIRST:
                START_PROFILE_NESTED(Trans2_findnotifyfirst);
                outsize = call_trans2findnotifyfirst(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findnotifyfirst);
                break;
 
        case TRANSACT2_FINDNOTIFYNEXT:
                START_PROFILE_NESTED(Trans2_findnotifynext);
                outsize = call_trans2findnotifynext(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_findnotifynext);
                break;
        case TRANSACT2_MKDIR:
                START_PROFILE_NESTED(Trans2_mkdir);
                outsize = call_trans2mkdir(conn, inbuf, outbuf, length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_mkdir);
                break;
 
        case TRANSACT2_GET_DFS_REFERRAL:
                START_PROFILE_NESTED(Trans2_get_dfs_referral);
                outsize = call_trans2getdfsreferral(conn,inbuf,outbuf,length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_get_dfs_referral);
                break;
        case TRANSACT2_IOCTL:
                START_PROFILE_NESTED(Trans2_ioctl);
                outsize = call_trans2ioctl(conn,inbuf,outbuf,length, bufsize,
-                                         &params, total_params, &data, total_data);
+                                         &params, total_params, &data, total_data, max_data_bytes);
                END_PROFILE_NESTED(Trans2_ioctl);
                break;
        default: