r10656: BIG merge from trunk. Features not copied over
[vlendec/samba-autobuild/.git] / source3 / smbd / trans2.c
index ca2c8a060dcbf590245a7d381fc5b20c7f0f666e..f0b7812a1e04dd8d50afe2aac48c95ec27390738 100644 (file)
@@ -3,6 +3,7 @@
    SMB transaction2 handling
    Copyright (C) Jeremy Allison                        1994-2003
    Copyright (C) Stefan (metze) Metzmacher     2003
+   Copyright (C) Volker Lendecke               2005
 
    Extensively modified by Andrew Tridgell, 1995
 
 
 #include "includes.h"
 
-extern int Protocol;
+extern int max_send;
+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 +34,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,22 +55,24 @@ 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;
 
+       if(S_ISDIR(sbuf->st_mode)) {
+               return 0;
+       }
+
 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
        ret = (SMB_BIG_UINT)STAT_ST_BLOCKSIZE * (SMB_BIG_UINT)sbuf->st_blocks;
 #else
        ret = (SMB_BIG_UINT)get_file_size(*sbuf);
 #endif
 
-       if (!ret && fsp && fsp->initial_allocation_size)
-               ret = fsp->initial_allocation_size;
+       if (fsp && fsp->initial_allocation_size)
+               ret = MAX(ret,fsp->initial_allocation_size);
 
-       ret = smb_roundup(ret);
-
-       return ret;
+       return smb_roundup(conn, ret);
 }
 
 /****************************************************************************
@@ -96,11 +100,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,13 +114,13 @@ 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;
        }
 
-       if (fsp && fsp->fd != -1) {
-               sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fd, ea_name, val, attr_size);
+       if (fsp && fsp->fh->fd != -1) {
+               sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, ea_name, val, attr_size);
        } else {
                sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
        }
@@ -135,7 +134,7 @@ static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
                return False;
        }
 
-       DEBUG(10,("get_ea_value: EA %s is of length %d: ", ea_name, sizeret));
+       DEBUG(10,("get_ea_value: EA %s is of length %u: ", ea_name, (unsigned int)sizeret));
        dump_data(10, val, sizeret);
 
        pea->flags = 0;
@@ -144,7 +143,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 +152,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,10 +169,10 @@ 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++) {
-               if (fsp && fsp->fd != -1) {
-                       sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fd, ea_namelist, ea_namelist_size);
+       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->fh->fd != -1) {
+                       sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fh->fd, ea_namelist, ea_namelist_size);
                } else {
                        sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, ea_namelist_size);
                }
@@ -187,7 +187,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 = %u\n", (unsigned int)sizeret ));
 
        if (sizeret) {
                for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p) + 1) {
@@ -196,7 +196,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,8 +208,8 @@ 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",
-                                       *pea_total_len, dos_ea_name,
+                               DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len = %u\n",
+                                       (unsigned int)*pea_total_len, dos_ea_name,
                                        (unsigned int)listp->ea.value.length ));
                        }
                        DLIST_ADD_END(ea_list_head, listp, tmp);
@@ -220,7 +220,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", (unsigned int)*pea_total_len));
        return ea_list_head;
 }
 
@@ -229,34 +229,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 +269,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 +283,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 +296,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 +313,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, (unsigned int)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->fh->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->fh->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->fh->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->fh->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. */
+
+               /* 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));
+       }
+
+       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 (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;
+       if (data_size < 6) {
+               return NULL;
        }
 
-       pdata += 4;
+       eal->ea.flags = CVAL(pdata,0);
        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;
+       val_len = SVAL(pdata,2);
+
+       if (4 + namelen + 1 + val_len > data_size) {
+               return NULL;
+       }
+
+       /* 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 (pdata[namelen] != '\0') {
-               DEBUG(10,("set_ea: ea name not null terminated\n"));
-               return NT_STATUS_INVALID_PARAMETER;
+       eal->ea.value = data_blob(NULL, (size_t)val_len + 1);
+       if (!eal->ea.value.data) {
+               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);
+       memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
 
-       canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
+       /* 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--;
 
-       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);
+       if (pbytes_used) {
+               *pbytes_used = 4 + namelen + 1 + val_len;
        }
 
-       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;
-       }
+       DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
+       dump_data(10, (const char *)eal->ea.value.data, eal->ea.value.length);
 
-       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);
+       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;
 }
 
 /****************************************************************************
@@ -448,7 +575,6 @@ static int send_trans2_replies(char *outbuf,
         global struct. These different max_xmit variables should
         be merged as this is now too confusing */
 
-       extern int max_send;
        int data_to_send = datasize;
        int params_to_send = paramsize;
        int useable_space;
@@ -465,6 +591,7 @@ static int send_trans2_replies(char *outbuf,
        /* If there genuinely are no parameters or data to send just send the empty packet */
 
        if(params_to_send == 0 && data_to_send == 0) {
+               show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf))
                        exit_server("send_trans2_replies: send_smb failed.");
                return 0;
@@ -559,6 +686,7 @@ static int send_trans2_replies(char *outbuf,
                        params_to_send, data_to_send, paramsize, datasize));
 
                /* Send the packet */
+               show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf))
                        exit_server("send_trans2_replies: send_smb failed.");
 
@@ -584,40 +712,55 @@ 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;
-       int16 open_mode;
-       int16 open_attr;
+       char *pdata = *ppdata;
+       int deny_mode;
+       int32 open_attr;
        BOOL oplock_request;
 #if 0
        BOOL return_additional_info;
        int16 open_sattr;
        time_t open_time;
 #endif
-       int16 open_ofun;
+       int open_ofun;
        int32 open_size;
        char *pname;
        pstring fname;
        SMB_OFF_T size=0;
-       int fmode=0,mtime=0,rmode;
+       int fattr=0,mtime=0;
        SMB_INO_T inode = 0;
        SMB_STRUCT_STAT sbuf;
        int smb_action = 0;
        BOOL bad_path = False;
        files_struct *fsp;
+       TALLOC_CTX *ctx = NULL;
+       struct ea_list *ea_list = NULL;
+       uint16 flags = 0;
        NTSTATUS status;
+       uint32 access_mask;
+       uint32 share_mode;
+       uint32 create_disposition;
+       uint32 create_options = 0;
 
        /*
         * 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);
+       flags = SVAL(params, 0);
+       deny_mode = SVAL(params, 2);
        open_attr = SVAL(params,6);
-       oplock_request = (((SVAL(params,0)|(1<<1))>>1) | ((SVAL(params,0)|(1<<2))>>1));
+        oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
+        if (oplock_request) {
+                oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
+        }
+
 #if 0
        return_additional_info = BITSETW(params,0);
        open_sattr = SVAL(params, 4);
@@ -627,16 +770,18 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
        open_size = IVAL(params,14);
        pname = &params[28];
 
-       if (IS_IPC(conn))
+       if (IS_IPC(conn)) {
                return(ERROR_DOS(ERRSRV,ERRaccess));
+       }
 
        srvstr_get_path(inbuf, fname, pname, sizeof(fname), -1, STR_TERMINATE, &status, False);
        if (!NT_STATUS_IS_OK(status)) {
                return ERROR_NT(status);
        }
 
-       DEBUG(3,("trans2open %s mode=%d attr=%d ofun=%d size=%d\n",
-               fname,open_mode, open_attr, open_ofun, open_size));
+       DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
+               fname, (unsigned int)deny_mode, (unsigned int)open_attr,
+               (unsigned int)open_ofun, open_size));
 
        /* XXXX we need to handle passed times, sattr and flags */
 
@@ -649,42 +794,96 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
-       fsp = open_file_shared(conn,fname,&sbuf,open_mode,open_ofun,(uint32)open_attr,
-               oplock_request, &rmode,&smb_action);
+       if (!map_open_params_to_ntcreate(fname, deny_mode, open_ofun,
+                               &access_mask,
+                               &share_mode,
+                               &create_disposition,
+                               &create_options)) {
+               return ERROR_DOS(ERRDOS, ERRbadaccess);
+       }
+
+       /* 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_ntcreate(conn,fname,&sbuf,
+               access_mask,
+               share_mode,
+               create_disposition,
+               create_options,
+               open_attr,
+               oplock_request,
+               &smb_action);
       
        if (!fsp) {
+               talloc_destroy(ctx);
                if (open_was_deferred(SVAL(inbuf,smb_mid))) {
                        /* We have re-scheduled this call. */
-                       clear_cached_errors();
                        return -1;
                }
                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRnoaccess);
        }
 
        size = get_file_size(sbuf);
-       fmode = dos_mode(conn,fname,&sbuf);
+       fattr = dos_mode(conn,fname,&sbuf);
        mtime = sbuf.st_mtime;
        inode = sbuf.st_ino;
-       if (fmode & aDIR) {
+       if (fattr & 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, 30);
+       if( params == NULL ) {
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *pparams = params;
 
-       memset((char *)params,'\0',28);
        SSVAL(params,0,fsp->fnum);
-       SSVAL(params,2,fmode);
+       SSVAL(params,2,open_attr);
        put_dos_date2(params,4, mtime);
        SIVAL(params,8, (uint32)size);
-       SSVAL(params,12,rmode);
+       SSVAL(params,12,deny_mode);
+       SSVAL(params,14,0); /* open_type - file or directory. */
+       SSVAL(params,16,0); /* open_state - only valid for IPC device. */
 
-       if (oplock_request && lp_fake_oplocks(SNUM(conn)))
+       if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
                smb_action |= EXTENDED_OPLOCK_GRANTED;
+       }
 
        SSVAL(params,18,smb_action);
 
@@ -692,9 +891,16 @@ static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, i
         * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
         */
        SIVAL(params,20,inode);
+       SSVAL(params,24,0); /* Padding. */
+       if (flags & 8) {
+               uint32 ea_size = estimate_ea_size(conn, fsp, fname);
+               SIVAL(params, 26, ea_size);
+       } else {
+               SIVAL(params, 26, 0);
+       }
+
        /* Send the required number of replies */
-       send_trans2_replies(outbuf, bufsize, params, 28, *ppdata, 0);
+       send_trans2_replies(outbuf, bufsize, params, 30, *ppdata, 0);
 
        return -1;
 }
@@ -800,33 +1006,18 @@ 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.
 ****************************************************************************/
 
 static BOOL get_lanman2_dir_entry(connection_struct *conn,
                                  void *inbuf, void *outbuf,
-                                char *path_mask,int dirtype,int info_level,
+                                char *path_mask,uint32 dirtype,int info_level,
                                 int requires_resume_key,
                                 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,16 +1027,18 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
        pstring fname;
        char *p, *q, *pdata = *ppdata;
        uint32 reskey=0;
-       int prev_dirpos=0;
-       int mode=0;
+       long prev_dirpos=0;
+       uint32 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 */
+       uint32 nt_extmode; /* Used for NT connections instead of mode */
        BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+       BOOL check_mangled_names = lp_manglednames(SNUM(conn));
 
        *fname = 0;
        *out_of_space = False;
@@ -863,12 +1056,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 +1072,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);
@@ -890,7 +1083,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
                        got_match = mask_match(fname, mask, conn->case_sensitive);
 
-               if(!got_match && !mangle_is_8_3(fname, False)) {
+               if(!got_match && check_mangled_names && !mangle_is_8_3(fname, False, SNUM(conn))) {
 
                        /*
                         * It turns out that NT matches wildcards against
@@ -922,14 +1115,14 @@ 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 */
 
                                if(lp_host_msdfs() && 
                                   lp_msdfs_root(SNUM(conn)) &&
-                                  is_msdfs_link(conn, pathreal, NULL, NULL,
+                                  is_msdfs_link(NULL,conn, pathreal, NULL, NULL,
                                                 &sbuf)) {
 
                                        DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
@@ -945,13 +1138,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 +1155,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,24 +1172,24 @@ 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;
                        }
-                       put_dos_date2(p,l1_fdateCreation,cdate);
-                       put_dos_date2(p,l1_fdateLastAccess,adate);
-                       put_dos_date2(p,l1_fdateLastWrite,mdate);
-                       SIVAL(p,l1_cbFile,(uint32)file_size);
-                       SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size);
-                       SSVAL(p,l1_attrFile,mode);
-                       p += l1_achName;
+                       put_dos_date2(p,0,cdate);
+                       put_dos_date2(p,4,adate);
+                       put_dos_date2(p,8,mdate);
+                       SIVAL(p,12,(uint32)file_size);
+                       SIVAL(p,16,(uint32)allocation_size);
+                       SSVAL(p,20,mode);
+                       p += 23;
                        nameptr = p;
                        p += align_string(outbuf, p, 0);
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
@@ -1011,23 +1209,23 @@ 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;
                        }
-                       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);
+                       put_dos_date2(p,0,cdate);
+                       put_dos_date2(p,4,adate);
+                       put_dos_date2(p,8,mdate);
+                       SIVAL(p,12,(uint32)file_size);
+                       SIVAL(p,16,(uint32)allocation_size);
+                       SSVAL(p,20,mode);
                        {
                                unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
-                               SIVAL(p,l2_cbList,ea_size); /* Extended attributes */
+                               SIVAL(p,22,ea_size); /* Extended attributes */
                        }
-                       p += l2_achName;
+                       p += 27;
                        nameptr = p - 1;
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN);
                        if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
@@ -1048,9 +1246,66 @@ 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,0,cdate);
+                       put_dos_date2(p,4,adate);
+                       put_dos_date2(p,8,mdate);
+                       SIVAL(p,12,(uint32)file_size);
+                       SIVAL(p,16,(uint32)allocation_size);
+                       SSVAL(p,20,mode);
+                       p += 22; /* 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);
+                       was_8_3 = mangle_is_8_3(fname, True, SNUM(conn));
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
                        put_long_date(p,cdate); p += 8;
@@ -1070,22 +1325,24 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                         * IMPORTANT as not doing so will trigger
                         * a Win2k client bug. JRA.
                         */
-                       memset(p,'\0',26);
-                       if (!was_8_3 && lp_manglednames(SNUM(conn))) {
+                       if (!was_8_3 && check_mangled_names) {
                                pstring mangled_name;
                                pstrcpy(mangled_name, fname);
                                mangle_map(mangled_name,True,True,SNUM(conn));
                                mangled_name[12] = 0;
                                len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
+                               if (len < 24) {
+                                       memset(p + 2 + len,'\0',24 - len);
+                               }
                                SSVAL(p, 0, len);
                        } else {
-                               SSVAL(p,0,0);
-                               *(p+2) = 0;
+                               memset(p,'\0',26);
                        }
                        p += 2 + 24;
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
                        SIVAL(q,0,len);
                        p += len;
+                       SIVAL(p,0,0); /* Ensure any padding is null. */
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
                        SIVAL(pdata,0,len);
@@ -1106,6 +1363,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        len = srvstr_push(outbuf, p + 4, fname, -1, STR_TERMINATE_ASCII);
                        SIVAL(p,0,len);
                        p += 4 + len;
+                       SIVAL(p,0,0); /* Ensure any padding is null. */
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
                        SIVAL(pdata,0,len);
@@ -1133,6 +1391,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        SIVAL(q, 0, len);
                        p += len;
 
+                       SIVAL(p,0,0); /* Ensure any padding is null. */
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
                        SIVAL(pdata,0,len);
@@ -1149,6 +1408,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
                        SIVAL(p, -4, len);
                        p += len;
+                       SIVAL(p,0,0); /* Ensure any padding is null. */
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
                        SIVAL(pdata,0,len);
@@ -1178,6 +1438,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
                        SIVAL(q, 0, len);
                        p += len; 
+                       SIVAL(p,0,0); /* Ensure any padding is null. */
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
                        SIVAL(pdata,0,len);
@@ -1186,7 +1447,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
                        DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
-                       was_8_3 = mangle_is_8_3(fname, True);
+                       was_8_3 = mangle_is_8_3(fname, True, SNUM(conn));
                        p += 4;
                        SIVAL(p,0,reskey); p += 4;
                        put_long_date(p,cdate); p += 8;
@@ -1206,17 +1467,19 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                         * IMPORTANT as not doing so will trigger
                         * a Win2k client bug. JRA.
                         */
-                       memset(p,'\0',26);
-                       if (!was_8_3 && lp_manglednames(SNUM(conn))) {
+                       if (!was_8_3 && check_mangled_names) {
                                pstring mangled_name;
                                pstrcpy(mangled_name, fname);
                                mangle_map(mangled_name,True,True,SNUM(conn));
                                mangled_name[12] = 0;
                                len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
                                SSVAL(p, 0, len);
+                               if (len < 24) {
+                                       memset(p + 2 + len,'\0',24 - len);
+                               }
+                               SSVAL(p, 0, len);
                        } else {
-                               SSVAL(p,0,0);
-                               *(p+2) = 0;
+                               memset(p,'\0',26);
                        }
                        p += 26;
                        SSVAL(p,0,0); p += 2; /* Reserved ? */
@@ -1225,6 +1488,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
                        SIVAL(q,0,len);
                        p += len;
+                       SIVAL(p,0,0); /* Ensure any padding is null. */
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
                        SIVAL(pdata,0,len);
@@ -1242,7 +1506,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 */
@@ -1282,6 +1546,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
 
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
                        p += len;
+                       SIVAL(p,0,0); /* Ensure any padding is null. */
 
                        len = PTR_DIFF(p, pdata);
                        len = (len + 3) & ~3;
@@ -1298,14 +1563,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,17 +1582,17 @@ 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);
+       uint32 dirtype = SVAL(params,0);
        int maxentries = SVAL(params,2);
        uint16 findfirst_flags = SVAL(params,4);
        BOOL close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
@@ -1336,8 +1601,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,16 +1612,19 @@ 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;
 
-       DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \
+       DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
 close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
-               dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
+               (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
                info_level, max_data_bytes));
 
        if (!maxentries) {
@@ -1365,8 +1633,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 +1656,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 +1681,62 @@ 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)
-               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))) {
-               dptr_close(&dptr_num);
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid), mask, dirtype);
+       if (dptr_num < 0) {
+               talloc_destroy(ea_ctx);
+               return(UNIXERROR(ERRDOS,ERRbadfile));
        }
 
-       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 +1763,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 +1785,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 +1795,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 +1816,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));
 
@@ -1531,7 +1835,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
         * (see PR#13758). JRA.
         */
 
-       if(!mangle_is_8_3_wildcards( mask, False))
+       if(!mangle_is_8_3_wildcards( mask, False, SNUM(conn)))
                mangle_map(mask, True, True, SNUM(conn));
 
        return(-1);
@@ -1542,14 +1846,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 +1871,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 +1913,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 +1929,65 @@ 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 +1997,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 +2019,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, SNUM(conn))) {
+                       mangle_check_cache(resume_name, sizeof(resume_name)-1, SNUM(conn));
                }
 
                /*
-                * 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 +2058,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 +2080,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 +2092,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 +2110,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 +2131,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 +2144,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 +2182,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 +2231,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 +2245,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 +2277,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;
@@ -2032,7 +2346,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        
                        fsp.conn = conn;
                        fsp.fnum = -1;
-                       fsp.fd = -1;
+                       fsp.fh->fd = -1;
                        
                        /* access check */
                        if (current_user.uid != 0) {
@@ -2086,7 +2400,8 @@ 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|
+                                       CIFS_UNIX_POSIX_PATHNAMES_CAP))); /* We have POSIX ACLs and pathname capability. */
                        break;
 
                case SMB_MAC_QUERY_FS_INFO:
@@ -2112,101 +2427,134 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
        return -1;
 }
 
-#ifdef HAVE_SYS_QUOTAS
 /****************************************************************************
  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;
-       files_struct *fsp = NULL;
        uint16 info_level;
        int outsize;
-       SMB_NTQUOTA_STRUCT quotas;
-       
-       ZERO_STRUCT(quotas);
 
-       DEBUG(10,("call_trans2setfsinfo: SET_FS_QUOTA: for service [%s]\n",lp_servicename(SNUM(conn))));
-
-       /* access check */
-       if ((current_user.uid != 0)||!CAN_WRITE(conn)) {
-               DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
-                       lp_servicename(SNUM(conn)),conn->user));
-               return ERROR_DOS(ERRSRV,ERRaccess);
-       }
+       DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
 
        /*  */
        if (total_params < 4) {
                DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
                        total_params));
-               return ERROR_DOS(ERRDOS,ERRinvalidparam);
-       }
-
-       fsp = file_fsp(params,0);
-
-       if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) {
-               DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
-               return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
        }
 
        info_level = SVAL(params,2);
 
        switch(info_level) {
-               case SMB_FS_QUOTA_INFORMATION:
-                       /* note: normaly there're 48 bytes,
-                        * but we didn't use the last 6 bytes for now 
-                        * --metze 
-                        */
-                       if (total_data < 42) {
-                               DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
-                                       total_data));
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
+               case SMB_SET_CIFS_UNIX_INFO:
+                       {
+                               uint16 client_unix_major;
+                               uint16 client_unix_minor;
+                               uint32 client_unix_cap_low;
+                               uint32 client_unix_cap_high;
+
+                               if (!lp_unix_extensions()) {
+                                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                               }
+
+                               /* There should be 12 bytes of capabilities set. */
+                               if (total_data < 8) {
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                               }
+                               client_unix_major = SVAL(pdata,0);
+                               client_unix_minor = SVAL(pdata,2);
+                               client_unix_cap_low = IVAL(pdata,4);
+                               client_unix_cap_high = IVAL(pdata,8);
+                               /* Just print these values for now. */
+                               DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \
+cap_low = 0x%x, cap_high = 0x%x\n",
+                                       (unsigned int)client_unix_major,
+                                       (unsigned int)client_unix_minor,
+                                       (unsigned int)client_unix_cap_low,
+                                       (unsigned int)client_unix_cap_high ));
+
+                               /* Here is where we must switch to posix pathname processing... */
+                               lp_set_posix_pathnames();
+                               mangle_change_to_posix();
+                               break;
                        }
+               case SMB_FS_QUOTA_INFORMATION:
+                       {
+                               files_struct *fsp = NULL;
+                               SMB_NTQUOTA_STRUCT quotas;
+       
+                               ZERO_STRUCT(quotas);
+
+                               /* access check */
+                               if ((current_user.uid != 0)||!CAN_WRITE(conn)) {
+                                       DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
+                                               lp_servicename(SNUM(conn)),conn->user));
+                                       return ERROR_DOS(ERRSRV,ERRaccess);
+                               }
+
+                               /* note: normaly there're 48 bytes,
+                                * but we didn't use the last 6 bytes for now 
+                                * --metze 
+                                */
+                               fsp = file_fsp(params,0);
+                               if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) {
+                                       DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
+                                       return ERROR_NT(NT_STATUS_INVALID_HANDLE);
+                               }
+
+                               if (total_data < 42) {
+                                       DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
+                                               total_data));
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                               }
                        
-                       /* unknown_1 24 NULL bytes in pdata*/
+                               /* unknown_1 24 NULL bytes in pdata*/
                
-                       /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
-                       quotas.softlim = (SMB_BIG_UINT)IVAL(pdata,24);
+                               /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
+                               quotas.softlim = (SMB_BIG_UINT)IVAL(pdata,24);
 #ifdef LARGE_SMB_OFF_T
-                       quotas.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32);
+                               quotas.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32);
 #else /* LARGE_SMB_OFF_T */
-                       if ((IVAL(pdata,28) != 0)&&
-                               ((quotas.softlim != 0xFFFFFFFF)||
-                               (IVAL(pdata,28)!=0xFFFFFFFF))) {
-                               /* more than 32 bits? */
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
-                       }
+                               if ((IVAL(pdata,28) != 0)&&
+                                       ((quotas.softlim != 0xFFFFFFFF)||
+                                       (IVAL(pdata,28)!=0xFFFFFFFF))) {
+                                       /* more than 32 bits? */
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                               }
 #endif /* LARGE_SMB_OFF_T */
                
-                       /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
-                       quotas.hardlim = (SMB_BIG_UINT)IVAL(pdata,32);
+                               /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
+                               quotas.hardlim = (SMB_BIG_UINT)IVAL(pdata,32);
 #ifdef LARGE_SMB_OFF_T
-                       quotas.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32);
+                               quotas.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32);
 #else /* LARGE_SMB_OFF_T */
-                       if ((IVAL(pdata,36) != 0)&&
-                               ((quotas.hardlim != 0xFFFFFFFF)||
-                               (IVAL(pdata,36)!=0xFFFFFFFF))) {
-                               /* more than 32 bits? */
-                               return ERROR_DOS(ERRDOS,ERRunknownlevel);
-                       }
+                               if ((IVAL(pdata,36) != 0)&&
+                                       ((quotas.hardlim != 0xFFFFFFFF)||
+                                       (IVAL(pdata,36)!=0xFFFFFFFF))) {
+                                       /* more than 32 bits? */
+                                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+                               }
 #endif /* LARGE_SMB_OFF_T */
                
-                       /* quota_flags 2 bytes **/
-                       quotas.qflags = SVAL(pdata,40);
+                               /* quota_flags 2 bytes **/
+                               quotas.qflags = SVAL(pdata,40);
                
-                       /* unknown_2 6 NULL bytes follow*/
+                               /* unknown_2 6 NULL bytes follow*/
                
-                       /* now set the quotas */
-                       if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
-                               DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
-                               return ERROR_DOS(ERRSRV,ERRerror);
-                       }
+                               /* now set the quotas */
+                               if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
+                                       DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+                                       return ERROR_DOS(ERRSRV,ERRerror);
+                               }
                        
-                       break;
+                               break;
+                       }
                default:
                        DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
                                info_level));
@@ -2224,11 +2572,10 @@ static int call_trans2setfsinfo(connection_struct *conn,
 
        return outsize;
 }
-#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,25 +2592,141 @@ 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,
+                                       unsigned int tran_call,
+                                       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);
        uint16 info_level;
        int mode=0;
+       int nlink;
        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,7 +2739,9 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
        int len;
        time_t c_time;
        files_struct *fsp = NULL;
-       uint32 desired_access = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
+       TALLOC_CTX *ea_ctx = NULL;
+       struct ea_list *ea_list = NULL;
+       uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
 
        if (!params)
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
@@ -2284,8 +2749,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);
@@ -2300,7 +2766,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        pstrcpy(fname, fsp->fsp_name);
                        /* We know this name is ok, it's already passed the checks. */
                        
-               } else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
+               } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) {
                        /*
                         * This is actually a QFILEINFO on a directory
                         * handle (returned from an NT SMB). NT5.0 seems
@@ -2320,7 +2786,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                        }
 
-                       delete_pending = fsp->is_directory ? fsp->directory_delete_on_close : 0;
+                       delete_pending =
+                               get_delete_on_close_flag(sbuf.st_dev,
+                                                        sbuf.st_ino,
+                                                        fname);
                } else {
                        /*
                         * Original code - this is an open file.
@@ -2328,20 +2797,24 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        CHECK_FSP(fsp,conn);
 
                        pstrcpy(fname, fsp->fsp_name);
-                       if (SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
+                       if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) {
                                DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno)));
                                return(UNIXERROR(ERRDOS,ERRbadfid));
                        }
-                       pos = fsp->position_information;
-                       delete_pending = fsp->delete_on_close;
-                       desired_access = fsp->desired_access;
+                       pos = fsp->fh->position_information;
+                       delete_pending = 
+                               get_delete_on_close_flag(sbuf.st_dev,
+                                                        sbuf.st_ino,
+                                                        fname);
+                       access_mask = fsp->access_mask;
                }
        } else {
                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);
 
@@ -2373,6 +2846,24 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
                        return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadpath);
                }
+
+               delete_pending = get_delete_on_close_flag(sbuf.st_dev,
+                                                         sbuf.st_ino,
+                                                         fname);
+               if (delete_pending) {
+                       return ERROR_NT(NT_STATUS_DELETE_PENDING);
+               }
+       }
+
+       nlink = sbuf.st_nlink;
+
+       if ((nlink > 0) && S_ISDIR(sbuf.st_mode)) {
+               /* NTFS does not seem to count ".." */
+               nlink -= 1;
+       }
+
+       if ((nlink > 0) && delete_pending) {
+               nlink -= 1;
        }
 
        if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions())
@@ -2393,30 +2884,79 @@ 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)
+       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);
 
-       params = Realloc(*pparams,2);
-       if (params == NULL)
-         return ERROR_DOS(ERRDOS,ERRnomem);
+               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);
+               }
+
+               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);
+       SSVAL(params,0,0);
        data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
-       pdata = Realloc(*ppdata, data_size); 
-       if ( pdata == NULL )
-               return ERROR_DOS(ERRDOS,ERRnomem);
+       pdata = SMB_REALLOC(*ppdata, data_size); 
+       if ( pdata == NULL ) {
+               talloc_destroy(ea_ctx);
+               return ERROR_NT(NT_STATUS_NO_MEMORY);
+       }
        *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);
-       }
+       c_time = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
 
-       memset((char *)pdata,'\0',data_size);
+       allocation_size = get_allocation_size(conn,fsp,&sbuf);
 
-       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 (fsp1 && fsp1->initial_allocation_size) {
+                       allocation_size = get_allocation_size(conn, fsp1, &sbuf);
+               }
+       }
 
        if (lp_dos_filetime_resolution(SNUM(conn))) {
                c_time &= ~1;
@@ -2451,13 +2991,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
                        data_size = 26;
-                       put_dos_date2(pdata,l1_fdateCreation,c_time);
-                       put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
-                       put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
-                       SIVAL(pdata,l1_cbFile,(uint32)file_size);
-                       SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
-                       SSVAL(pdata,l1_attrFile,mode);
-                       SIVAL(pdata,l1_attrFile+2,ea_size);
+                       put_dos_date2(pdata,0,c_time);
+                       put_dos_date2(pdata,4,sbuf.st_atime);
+                       put_dos_date2(pdata,8,sbuf.st_mtime); /* write time */
+                       SIVAL(pdata,12,(uint32)file_size);
+                       SIVAL(pdata,16,(uint32)allocation_size);
+                       SSVAL(pdata,20,mode);
+                       SIVAL(pdata,22,ea_size);
                        break;
                }
 
@@ -2471,22 +3011,52 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        param_size = 0;
                        break;
                        
-               case SMB_INFO_QUERY_EAS_FROM_LIST:
-                       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);
+               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"));
+
+                       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:
@@ -2514,7 +3084,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        DEBUG(5,("write: %s ", ctime(&sbuf.st_mtime)));
                        DEBUG(5,("change: %s ", ctime(&sbuf.st_mtime)));
                        DEBUG(5,("mode: %x\n", mode));
-
                        break;
 
                case SMB_FILE_STANDARD_INFORMATION:
@@ -2524,12 +3093,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        data_size = 24;
                        SOFF_T(pdata,0,allocation_size);
                        SOFF_T(pdata,8,file_size);
-                       if (delete_pending & sbuf.st_nlink)
-                               SIVAL(pdata,16,sbuf.st_nlink - 1);
-                       else
-                               SIVAL(pdata,16,sbuf.st_nlink);
-                       SCVAL(pdata,20,0);
+                       SIVAL(pdata,16,nlink);
+                       SCVAL(pdata,20,delete_pending?1:0);
                        SCVAL(pdata,21,(mode&aDIR)?1:0);
+                       SSVAL(pdata,22,0); /* Padding. */
                        break;
 
                case SMB_FILE_EA_INFORMATION:
@@ -2551,7 +3118,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
                        pstrcpy(short_name,base_name);
                        /* Mangle if not already 8.3 */
-                       if(!mangle_is_8_3(short_name, True)) {
+                       if(!mangle_is_8_3(short_name, True, SNUM(conn))) {
                                mangle_map(short_name,True,True,SNUM(conn));
                        }
                        len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_UNICODE);
@@ -2594,15 +3161,14 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        put_long_date(pdata+16,sbuf.st_mtime); /* write time */
                        put_long_date(pdata+24,sbuf.st_mtime); /* change time */
                        SIVAL(pdata,32,mode);
+                       SIVAL(pdata,36,0); /* padding. */
                        pdata += 40;
                        SOFF_T(pdata,0,allocation_size);
                        SOFF_T(pdata,8,file_size);
-                       if (delete_pending && sbuf.st_nlink)
-                               SIVAL(pdata,16,sbuf.st_nlink - 1);
-                       else
-                               SIVAL(pdata,16,sbuf.st_nlink);
+                       SIVAL(pdata,16,nlink);
                        SCVAL(pdata,20,delete_pending);
                        SCVAL(pdata,21,(mode&aDIR)?1:0);
+                       SSVAL(pdata,22,0);
                        pdata += 24;
                        SIVAL(pdata,0,ea_size);
                        pdata += 4; /* EA info */
@@ -2627,7 +3193,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                case SMB_FILE_ACCESS_INFORMATION:
                        DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
-                       SIVAL(pdata,0,desired_access);
+                       SIVAL(pdata,0,access_mask);
                        data_size = 4;
                        break;
 
@@ -2730,7 +3296,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,97 +3368,92 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                                break;
                        }
 
-               default:
-                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
-       }
-
-       send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size);
-
-       return(-1);
-}
+#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;
 
-/****************************************************************************
- Deal with the internal needs of setting the delete on close flag. Note that
- as the tdb locking is recursive, it is safe to call this from within 
- open_file_shared. JRA.
-****************************************************************************/
+                               if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) {
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
+                               } else {
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
+                               }
 
-NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL delete_on_close, uint32 dosmode)
-{
-       if (delete_on_close) {
-               /*
-                * Only allow delete on close for writable files.
-                */
+                               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 (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 (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);
+                               }
 
-               /*
-                * Only allow delete on close for writable shares.
-                */
+                               num_file_acls = count_acl_entries(conn, file_acl);
+                               num_def_acls = count_acl_entries(conn, def_acl);
 
-               if (!CAN_WRITE(fsp->conn)) {
-                       DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but write access denied on share.\n",
-                               fsp->fsp_name ));
-                       return NT_STATUS_ACCESS_DENIED;
-               }
+                               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);
+                               }
 
-               /*
-                * Only allow delete on close for files/directories opened with delete intent.
-                */
+                               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 (!(fsp->desired_access & DELETE_ACCESS)) {
-                       DEBUG(10,("set_delete_on_close_internal: file %s delete on close flag set but delete access denied.\n",
-                               fsp->fsp_name ));
-                       return NT_STATUS_ACCESS_DENIED;
-               }
-       }
+                               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
 
-       if(fsp->is_directory) {
-               fsp->directory_delete_on_close = delete_on_close;
-               DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, directory %s\n",
-                       delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
-       } else {
-               fsp->delete_on_close = delete_on_close;
-               DEBUG(10, ("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n",
-                       delete_on_close ? "Added" : "Removed", fsp->fnum, fsp->fsp_name ));
+               default:
+                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
        }
 
-       return NT_STATUS_OK;
-}
-
-/****************************************************************************
- Sets the delete on close flag over all share modes on this file.
- Modify the share mode entry for all files open
- on this device and inode to tell other smbds we have
- changed the delete on close flag. This will be noticed
- in the close code, the last closer will delete the file
- if flag is set.
-****************************************************************************/
-
-NTSTATUS set_delete_on_close_over_all(files_struct *fsp, BOOL delete_on_close)
-{
-       DEBUG(10,("set_delete_on_close_over_all: %s delete on close flag for fnum = %d, file %s\n",
-               delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name ));
-
-       if (fsp->is_directory || fsp->is_stat)
-               return NT_STATUS_OK;
-
-       if (lock_share_entry_fsp(fsp) == False)
-               return NT_STATUS_ACCESS_DENIED;
-
-       if (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) {
-               DEBUG(0,("set_delete_on_close_over_all: failed to change delete on close flag for file %s\n",
-                       fsp->fsp_name ));
-               unlock_share_entry_fsp(fsp);
-               return NT_STATUS_ACCESS_DENIED;
-       }
+       send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size);
 
-       unlock_share_entry_fsp(fsp);
-       return NT_STATUS_OK;
+       return(-1);
 }
 
 /****************************************************************************
@@ -2983,13 +3544,13 @@ 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,
+                                       unsigned int tran_call,
+                                       char **pparams, int total_params, char **ppdata, int total_data,
+                                       unsigned int max_data_bytes)
 {
        char *params = *pparams;
        char *pdata = *ppdata;
-       uint16 tran_call = SVAL(inbuf, smb_setup0);
        uint16 info_level;
        int dosmode=0;
        SMB_OFF_T size=0;
@@ -3008,15 +3569,17 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 
        ZERO_STRUCT(sbuf);
+       ZERO_STRUCT(tvs);
 
        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);    
 
-               if(fsp && (fsp->is_directory || fsp->fd == -1)) {
+               if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) {
                        /*
                         * This is actually a SETFILEINFO on a directory
                         * handle (returned from an NT SMB). NT5.0 seems
@@ -3032,7 +3595,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                         * Doing a DELETE_ON_CLOSE should cancel a print job.
                         */
                        if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
-                               fsp->share_mode = FILE_DELETE_ON_CLOSE;
+                               fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
 
                                DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name ));
        
@@ -3048,7 +3611,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        CHECK_FSP(fsp,conn);
 
                        pstrcpy(fname, fsp->fsp_name);
-                       fd = fsp->fd;
+                       fd = fsp->fh->fd;
 
                        if (SMB_VFS_FSTAT(fsp,fd,&sbuf) != 0) {
                                DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
@@ -3057,8 +3620,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 +3661,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 +3687,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 +3699,50 @@ 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;
+                       }
+
+                       /* We're done. We only get EA info in this call. */
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
+               }
 
+#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 +3753,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 +3769,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 +3783,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 +3802,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 +3816,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;
@@ -3225,29 +3828,21 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
  
                                if (fd == -1) {
                                        files_struct *new_fsp = NULL;
-                                       int access_mode = 0;
-                                       int action = 0;
-                                       if(global_oplock_break) {
-                                               /* Queue this file modify as we are the process of an oplock break.  */
-                                               DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
-                                               DEBUGADD(2,( "in oplock break state.\n"));
-                                               push_oplock_pending_smb_message(inbuf, length);
-                                               return -1;
-                                       }
  
-                                       new_fsp = open_file_shared1(conn, fname, &sbuf,FILE_WRITE_DATA,
-                                                                       SET_OPEN_MODE(DOS_OPEN_RDWR),
-                                                                       (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                                       new_fsp = open_file_ntcreate(conn, fname, &sbuf,
+                                                                       FILE_WRITE_DATA,
+                                                                       FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                                                       FILE_OPEN,
+                                                                       0,
                                                                        FILE_ATTRIBUTE_NORMAL,
-                                                                       INTERNAL_OPEN_ONLY, &access_mode, &action);
+                                                                       INTERNAL_OPEN_ONLY,
+                                                                       NULL);
  
-                                       if (new_fsp == NULL)
+                                       if (new_fsp == NULL) {
                                                return(UNIXERROR(ERRDOS,ERRbadpath));
+                                       }
                                        ret = vfs_allocate_file_space(new_fsp, allocation_size);
-                                       if (SMB_VFS_FSTAT(new_fsp,new_fsp->fd,&new_sbuf) != 0) {
+                                       if (SMB_VFS_FSTAT(new_fsp,new_fsp->fh->fd,&new_sbuf) != 0) {
                                                DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",
                                                                        new_fsp->fnum, strerror(errno)));
                                                ret = -1;
@@ -3274,8 +3869,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 +3889,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);
 
@@ -3305,25 +3902,30 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        if (fsp == NULL)
                                return(UNIXERROR(ERRDOS,ERRbadfid));
 
-                       status = set_delete_on_close_internal(fsp, delete_on_close, dosmode);
+                       status = can_set_delete_on_close(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))
-                               return ERROR_NT(status);
+                       if (!set_delete_on_close(fsp, delete_on_close)) {
+                               return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+                       }
 
-                       break;
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
                }
 
                case SMB_FILE_POSITION_INFORMATION:
                {
                        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
@@ -3334,9 +3936,38 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
 #endif /* LARGE_SMB_OFF_T */
                        DEBUG(10,("call_trans2setfilepathinfo: Set file position information for file %s to %.0f\n",
                                        fname, (double)position_information ));
-                       if (fsp)
-                               fsp->position_information = position_information;
-                       break;
+                       if (fsp) {
+                               fsp->fh->position_information = position_information;
+                       }
+
+                       /* We're done. We only get position info in this call. */
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
+               }
+
+               /* 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);
+                       }
+
+                       /* We're done. We only get mode info in this call. */
+                       SSVAL(params,0,0);
+                       send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
+                       return(-1);
                }
 
                /*
@@ -3347,8 +3978,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 +3993,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 +4029,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 +4199,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 +4243,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 +4339,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;
@@ -3694,35 +4361,56 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
 
                if (fd == -1) {
                        files_struct *new_fsp = NULL;
-                       int access_mode = 0;
-                       int action = 0;
-
-                       if(global_oplock_break) {
-                               /* Queue this file modify as we are the process of an oplock break.  */
-
-                               DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
-                               DEBUGADD(2,( "in oplock break state.\n"));
 
-                               push_oplock_pending_smb_message(inbuf, length);
-                               return -1;
-                       }
-
-                       new_fsp = open_file_shared(conn, fname, &sbuf,
-                                               SET_OPEN_MODE(DOS_OPEN_RDWR),
-                                               (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                       new_fsp = open_file_ntcreate(conn, fname, &sbuf,
+                                               FILE_WRITE_DATA,
+                                               FILE_SHARE_READ|FILE_SHARE_WRITE,
+                                               FILE_OPEN,
+                                               0,
                                                FILE_ATTRIBUTE_NORMAL,
-                                               INTERNAL_OPEN_ONLY, &access_mode, &action);
+                                               INTERNAL_OPEN_ONLY,
+                                               NULL);
        
-                       if (new_fsp == NULL)
+                       if (new_fsp == NULL) {
                                return(UNIXERROR(ERRDOS,ERRbadpath));
+                       }
                        ret = vfs_set_filelen(new_fsp, size);
                        close_file(new_fsp,True);
                } else {
                        ret = vfs_set_filelen(fsp, size);
                }
 
-               if (ret == -1)
+               if (ret == -1) {
                        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);
@@ -3735,22 +4423,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 +4455,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 +4521,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 +4545,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 +4570,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 +4597,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 +4608,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 +4634,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 +4648,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 +4741,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);
@@ -4018,18 +4755,6 @@ int reply_trans2(connection_struct *conn,
        unsigned int num_params, num_params_sofar, num_data, num_data_sofar;
        START_PROFILE(SMBtrans2);
 
-       if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) {
-               /* Queue this open message as we are the process of an
-                * oplock break.  */
-
-               DEBUG(2,("reply_trans2: queueing message trans2open due to being "));
-               DEBUGADD(2,( "in oplock break state.\n"));
-
-               push_oplock_pending_smb_message(inbuf, length);
-               END_PROFILE(SMBtrans2);
-               return -1;
-       }
-       
        if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
             && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
                END_PROFILE(SMBtrans2);
@@ -4057,22 +4782,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
@@ -4109,6 +4834,7 @@ int reply_trans2(connection_struct *conn,
                   of the parameter/data bytes */
                outsize = set_message(outbuf,0,0,True);
                srv_signing_trans_stop();
+               show_msg(outbuf);
                if (!send_smb(smbd_server_fd(),outbuf))
                        exit_server("reply_trans2: send_smb failed.");
 
@@ -4121,6 +4847,9 @@ int reply_trans2(connection_struct *conn,
                        unsigned int data_off;
 
                        ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
+
+                       /* We need to re-calcuate the new length after we've read the secondary packet. */
+                       length = smb_len(inbuf) + 4;
                        
                        /*
                         * The sequence number for the trans reply is always
@@ -4168,7 +4897,7 @@ int reply_trans2(connection_struct *conn,
                                        goto bad_param;
                                if (param_disp > total_params)
                                        goto bad_param;
-                               if ((smb_base(inbuf) + param_off + num_params >= inbuf + bufsize) ||
+                               if ((smb_base(inbuf) + param_off + num_params > inbuf + length) ||
                                                (smb_base(inbuf) + param_off + num_params < smb_base(inbuf)))
                                        goto bad_param;
                                if (params + param_disp < params)
@@ -4184,7 +4913,7 @@ int reply_trans2(connection_struct *conn,
                                        goto bad_param;
                                if (data_disp > total_data)
                                        goto bad_param;
-                               if ((smb_base(inbuf) + data_off + num_data >= inbuf + bufsize) ||
+                               if ((smb_base(inbuf) + data_off + num_data > inbuf + length) ||
                                                (smb_base(inbuf) + data_off + num_data < smb_base(inbuf)))
                                        goto bad_param;
                                if (data + data_disp < data)
@@ -4204,84 +4933,83 @@ 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;
 
-#ifdef HAVE_SYS_QUOTAS
        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
+
        case TRANSACT2_QPATHINFO:
        case TRANSACT2_QFILEINFO:
                START_PROFILE_NESTED(Trans2_qpathinfo);
-               outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, 
-                                         &params, total_params, &data, total_data);
+               outsize = call_trans2qfilepathinfo(conn, inbuf, outbuf, length, bufsize, tran_call,
+                                         &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);
+               outsize = call_trans2setfilepathinfo(conn, inbuf, outbuf, length, bufsize, tran_call,
+                                         &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: