Prefix VFS API macros with SMB_ for consistency and to avoid problems with VFS_ macro...
[tprouty/samba.git] / source / smbd / trans2.c
index 33828c32bd6988ecf6d37aa4db299d7e14909fcd..731fb9643bb9055a6e30f8745c7c8711ca1b755d 100644 (file)
@@ -1,7 +1,8 @@
 /* 
    Unix SMB/CIFS implementation.
    SMB transaction2 handling
-   Copyright (C) Jeremy Allison 1994-2001
+   Copyright (C) Jeremy Allison                        1994-2001
+   Copyright (C) Stefan (metze) Metzmacher     2003
 
    Extensively modified by Andrew Tridgell, 1995
 
@@ -28,17 +29,16 @@ 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;
 
-#define get_file_size(sbuf) (sbuf.st_size)
+#define get_file_size(sbuf) ((sbuf).st_size)
 
 /* given a stat buffer return the allocated size on disk, taking into
    account sparse files */
 SMB_BIG_UINT get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf)
 {
        SMB_BIG_UINT ret;
-#if defined(HAVE_STAT_ST_BLKSIZE) && defined(HAVE_STAT_ST_BLOCKS)
-       ret = (SMB_BIG_UINT)sbuf->st_blksize * (SMB_BIG_UINT)sbuf->st_blocks;
-#elif defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
+#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);
@@ -462,7 +462,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                                 BOOL *out_of_space, BOOL *got_exact_match,
                                 int *last_name_off)
 {
-       char *dname;
+       const char *dname;
        BOOL found = False;
        SMB_STRUCT_STAT sbuf;
        pstring mask;
@@ -551,12 +551,12 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        pstrcat(pathreal,dname);
 
                        if (INFO_LEVEL_IS_UNIX(info_level)) {
-                               if (vfs_lstat(conn,pathreal,&sbuf) != 0) {
+                               if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) {
                                        DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
                                                pathreal,strerror(errno)));
                                        continue;
                                }
-                       } else if (vfs_stat(conn,pathreal,&sbuf) != 0) {
+                       } else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
 
                                /* Needed to show the msdfs symlinks as 
                                 * directories */
@@ -628,7 +628,10 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        nameptr = p;
                        p += align_string(outbuf, p, 0);
                        len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
-                       SCVAL(nameptr, -1, len);
+                       if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS)
+                               SCVAL(nameptr, -1, len-2);
+                       else
+                               SCVAL(nameptr, -1, len-1);
                        p += len;
                        break;
 
@@ -646,10 +649,13 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
                        SIVAL(p,l2_cbList,0); /* No extended attributes */
                        p += l2_achName;
                        nameptr = p;
-                       len = srvstr_push(outbuf, p, fname, -1, STR_NOALIGN);
-                       SCVAL(p, -1, len);
+                       p += align_string(outbuf, p, 0);
+                       len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+                       if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS)
+                               SCVAL(nameptr, -1, len-2);
+                       else
+                               SCVAL(nameptr, -1, len-1);
                        p += len;
-                       *p++ = 0; /* craig from unisys pointed out we need this */
                        break;
 
                case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
@@ -1175,7 +1181,8 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                 */
 
                int current_pos, start_pos;
-               char *dname = NULL;
+               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--) {
@@ -1183,21 +1190,24 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
 
                        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 */
 
-                       /*
-                        * 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 != NULL)
-                               mangle_map( dname, False, True, SNUM(conn));
-
-                       if(dname && strcsequal( resume_name, dname)) {
-                               SeekDir(dirptr, current_pos+1);
-                               DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
-                               break;
+                               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;
+                               }
                        }
                }
 
@@ -1217,13 +1227,17 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                                 * here.
                                 */
 
-                               if(dname != NULL)
-                                       mangle_map( dname, False, True, SNUM(conn));
+                               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(dname && strcsequal( resume_name, dname)) {
-                                       SeekDir(dirptr, current_pos+1);
-                                       DEBUG(7,("call_trans2findnext: got match at pos %d\n", current_pos+1 ));
-                                       break;
+                                       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 */
@@ -1271,7 +1285,6 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
                dptr_close(&dptr_num); /* This frees up the saved mask */
        }
 
-
        /* Set up the return parameter block */
        SSVAL(params,0,numentries);
        SSVAL(params,2,finished);
@@ -1307,10 +1320,11 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
        char *vname = volume_label(SNUM(conn));
        int snum = SNUM(conn);
        char *fstype = lp_fstype(SNUM(conn));
+       int quota_flag = 0;
 
        DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
 
-       if(vfs_stat(conn,".",&st)!=0) {
+       if(SMB_VFS_STAT(conn,".",&st)!=0) {
                DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
                return ERROR_DOS(ERRSRV,ERRinvdevice);
        }
@@ -1327,7 +1341,7 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
                {
                        SMB_BIG_UINT dfree,dsize,bsize;
                        data_len = 18;
-                       conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);   
+                       SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize); 
                        SIVAL(pdata,l1_idFileSystem,st.st_dev);
                        SIVAL(pdata,l1_cSectorUnit,bsize/512);
                        SIVAL(pdata,l1_cUnit,dsize);
@@ -1356,8 +1370,15 @@ static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf
                case SMB_QUERY_FS_ATTRIBUTE_INFO:
                case SMB_FS_ATTRIBUTE_INFORMATION:
 
+
+#if defined(HAVE_SYS_QUOTAS)
+                       quota_flag = FILE_VOLUME_QUOTAS;
+#endif
+
                        SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
-                               (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)); /* FS ATTRIBUTES */
+                               (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)|
+                               quota_flag); /* FS ATTRIBUTES */
+
                        SIVAL(pdata,4,255); /* Max filename component length */
                        /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
                                and will think we can't do long filenames */
@@ -1395,7 +1416,7 @@ 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 = 24;
-                       conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+                       SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize);
                        block_size = lp_block_size(snum);
                        if (bsize < block_size) {
                                SMB_BIG_UINT factor = block_size/bsize;
@@ -1425,7 +1446,7 @@ 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;
-                       conn->vfs_ops.disk_free(conn,".",False,&bsize,&dfree,&dsize);
+                       SMB_VFS_DISK_FREE(conn,".",False,&bsize,&dfree,&dsize);
                        block_size = lp_block_size(snum);
                        if (bsize < block_size) {
                                SMB_BIG_UINT factor = block_size/bsize;
@@ -1459,6 +1480,78 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
                        SIVAL(pdata,4,0); /* characteristics */
                        break;
 
+#ifdef WITH_QUOTAS
+               case SMB_FS_QUOTA_INFORMATION:
+               /* 
+                * what we have to send --metze:
+                *
+                * Unknown1:            24 NULL bytes
+                * Soft Quota Treshold: 8 bytes seems like SMB_BIG_UINT or so
+                * Hard Quota Limit:    8 bytes seems like SMB_BIG_UINT or so
+                * Quota Flags:         2 byte :
+                * Unknown3:            6 NULL bytes
+                *
+                * 48 bytes total
+                * 
+                * details for Quota Flags:
+                * 
+                * 0x0020 Log Limit: log if the user exceeds his Hard Quota
+                * 0x0010 Log Warn:  log if the user exceeds his Soft Quota
+                * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
+                * 0x0001 Enable Quotas: enable quota for this fs
+                *
+                */
+               {
+                       /* we need to fake up a fsp here,
+                        * because its not send in this call
+                        */
+                       files_struct fsp;
+                       SMB_NTQUOTA_STRUCT quotas;
+                       
+                       ZERO_STRUCT(fsp);
+                       ZERO_STRUCT(quotas);
+                       
+                       fsp.conn = conn;
+                       fsp.fnum = -1;
+                       fsp.fd = -1;
+                       
+                       /* access check */
+                       if (conn->admin_user != True) {
+                               DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
+                                       lp_servicename(SNUM(conn)),conn->user));
+                               return ERROR_DOS(ERRDOS,ERRnoaccess);
+                       }
+                       
+                       if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
+                               DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
+                               return ERROR_DOS(ERRSRV,ERRerror);
+                       }
+
+                       data_len = 48;
+
+                       DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn))));          
+               
+                       /* Unknown1 24 NULL bytes*/
+                       SBIG_UINT(pdata,0,(SMB_BIG_UINT)0);
+                       SBIG_UINT(pdata,8,(SMB_BIG_UINT)0);
+                       SBIG_UINT(pdata,16,(SMB_BIG_UINT)0);
+               
+                       /* Default Soft Quota 8 bytes */
+                       SBIG_UINT(pdata,24,quotas.softlim);
+
+                       /* Default Hard Quota 8 bytes */
+                       SBIG_UINT(pdata,32,quotas.hardlim);
+       
+                       /* Quota flag 2 bytes */
+                       SSVAL(pdata,40,quotas.qflags);
+               
+                       /* Unknown3 6 NULL bytes */
+                       SSVAL(pdata,42,0);
+                       SIVAL(pdata,44,0);
+                       
+                       break;
+               }
+#endif /* WITH_QUOTAS */
                case SMB_FS_OBJECTID_INFORMATION:
                        data_len = 64;
                        break;
@@ -1500,6 +1593,7 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
        return -1;
 }
 
+#ifdef WITH_QUOTAS
 /****************************************************************************
  Reply to a TRANS2_SETFSINFO (set filesystem info).
 ****************************************************************************/
@@ -1508,18 +1602,110 @@ 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)
 {
-       /* Just say yes we did it - there is nothing that
-               can be set here so it doesn't matter. */
+       char *pdata = *ppdata;
+       char *params = *pparams;
+       files_struct *fsp = NULL;
+       uint16 info_level;
        int outsize;
-       DEBUG(3,("call_trans2setfsinfo\n"));
+       SMB_NTQUOTA_STRUCT quotas;
+       
+       ZERO_STRUCT(quotas);
 
-       if (!CAN_WRITE(conn))
+       DEBUG(10,("call_trans2setfsinfo: SET_FS_QUOTA: for service [%s]\n",lp_servicename(SNUM(conn))));
+
+       /* access check */
+       if ((conn->admin_user != True)||!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);
+       }
+
+       /*  */
+       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);
+       }
+
+       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);
+                       }
+                       
+                       /* unknown_1 24 NULL bytes in pdata*/
+               
+                       /* 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);
+#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);
+                       }
+#endif /* LARGE_SMB_OFF_T */
+               
+                       /* 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);
+#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);
+                       }
+#endif /* LARGE_SMB_OFF_T */
+               
+                       /* quota_flags 2 bytes **/
+                       quotas.qflags = SVAL(pdata,40);
+               
+                       /* 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);
+                       }
+                       
+                       break;
+               default:
+                       DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
+                               info_level));
+                       return ERROR_DOS(ERRDOS,ERRunknownlevel);
+                       break;
+       }
 
+       /* 
+        * sending this reply works fine, 
+        * but I'm not sure it's the same 
+        * like windows do...
+        * --metze
+        */ 
        outsize = set_message(outbuf,10,0,True);
 
        return outsize;
 }
+#endif /* WITH_QUOTAS */
 
 /****************************************************************************
  *  Utility function to set bad path error.
@@ -1578,7 +1764,20 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
 
-               if(fsp && (fsp->is_directory || fsp->fd == -1)) {
+               if(fsp && (fsp->fake_file_handle)) {
+                       /*
+                        * This is actually for the QUOTA_FAKE_FILE --metze
+                        */
+                                               
+                       pstrcpy(fname, fsp->fsp_name);
+                       unix_convert(fname,conn,0,&bad_path,&sbuf);
+                       if (!check_name(fname,conn)) {
+                               DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed for fake_file(%s)\n",fname,strerror(errno)));
+                               set_bad_path_error(errno, bad_path);
+                               return(UNIXERROR(ERRDOS,ERRbadpath));
+                       }
+                       
+               } else if(fsp && (fsp->is_directory || fsp->fd == -1)) {
                        /*
                         * This is actually a QFILEINFO on a directory
                         * handle (returned from an NT SMB). NT5.0 seems
@@ -1594,13 +1793,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                  
                        if (INFO_LEVEL_IS_UNIX(info_level)) {
                                /* Always do lstat for UNIX calls. */
-                               if (vfs_lstat(conn,fname,&sbuf)) {
-                                       DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno)));
+                               if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
+                                       DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
                                        set_bad_path_error(errno, bad_path);
                                        return(UNIXERROR(ERRDOS,ERRbadpath));
                                }
-                       } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno)));
+                       } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+                               DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
                                set_bad_path_error(errno, bad_path);
                                return(UNIXERROR(ERRDOS,ERRbadpath));
                        }
@@ -1613,11 +1812,11 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        CHECK_FSP(fsp,conn);
 
                        pstrcpy(fname, fsp->fsp_name);
-                       if (vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
+                       if (SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
                                DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno)));
                                return(UNIXERROR(ERRDOS,ERRbadfid));
                        }
-                       if((pos = fsp->conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1)
+                       if((pos = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_CUR)) == -1)
                                return(UNIXERROR(ERRDOS,ERRnoaccess));
 
                        delete_pending = fsp->delete_on_close;
@@ -1644,13 +1843,13 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                if (INFO_LEVEL_IS_UNIX(info_level)) {
                        /* Always do lstat for UNIX calls. */
-                       if (vfs_lstat(conn,fname,&sbuf)) {
-                               DEBUG(3,("call_trans2qfilepathinfo: vfs_lstat of %s failed (%s)\n",fname,strerror(errno)));
+                       if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
+                               DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
                                set_bad_path_error(errno, bad_path);
                                return(UNIXERROR(ERRDOS,ERRbadpath));
                        }
-               } else if (!VALID_STAT(sbuf) && vfs_stat(conn,fname,&sbuf)) {
-                       DEBUG(3,("call_trans2qfilepathinfo: vfs_stat of %s failed (%s)\n",fname,strerror(errno)));
+               } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
+                       DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
                        set_bad_path_error(errno, bad_path);
                        return(UNIXERROR(ERRDOS,ERRbadpath));
                }
@@ -1788,6 +1987,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 
                /* Get the 8.3 name - used if NT SMB was negotiated. */
                case SMB_QUERY_FILE_ALT_NAME_INFO:
+               case SMB_FILE_ALTERNATE_NAME_INFORMATION:
                {
                        pstring short_name;
 
@@ -1796,7 +1996,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                        if(!mangle_is_8_3(short_name, True)) {
                                mangle_map(short_name,True,True,SNUM(conn));
                        }
-                       len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_TERMINATE|STR_UPPER);
+                       len = srvstr_push(outbuf, pdata+4, short_name, -1, STR_UNICODE);
                        data_size = 4 + len;
                        SIVAL(pdata,0,len);
                        break;
@@ -1924,15 +2124,6 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
                }
 #endif
 
-               case SMB_FILE_ALTERNATE_NAME_INFORMATION:
-                       /* Last component of pathname. */
-                       {
-                               size_t byte_len = dos_PutUniCode(pdata+4,fname,max_data_bytes,False);
-                               SIVAL(pdata,0,byte_len);
-                               data_size = 4 + byte_len;
-                               break;
-                       }
-               
 #if 0
                /*
                 * NT4 server just returns "invalid query" to this - if we try to answer
@@ -2051,7 +2242,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
 #else
                                return(UNIXERROR(ERRDOS,ERRbadlink));
 #endif
-                               len = conn->vfs_ops.readlink(conn,fullpathname, buffer, sizeof(pstring)-1);     /* read link */
+                               len = SMB_VFS_READLINK(conn,fullpathname, buffer, sizeof(pstring)-1);     /* read link */
                                if (len == -1)
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                                buffer[len] = 0;
@@ -2103,59 +2294,42 @@ NTSTATUS set_delete_on_close_internal(files_struct *fsp, BOOL 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 ));
+       }
 
-               files_struct *iterate_fsp;
-
-               /*
-                * 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.
-                */
+       return NT_STATUS_OK;
+}
 
-               DEBUG(10,("set_delete_on_close_internal: %s delete on close flag for fnum = %d, file %s\n",
-                                       delete_on_close ? "Adding" : "Removing", fsp->fnum, fsp->fsp_name ));
+/****************************************************************************
+ 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.
+****************************************************************************/
 
-               if (lock_share_entry_fsp(fsp) == False)
-                               return NT_STATUS_ACCESS_DENIED;
+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 (!modify_delete_flag(fsp->dev, fsp->inode, delete_on_close)) {
-                       DEBUG(0,("set_delete_on_close_internal: failed to change delete on close flag for file %s\n",
-                                       fsp->fsp_name ));
-                       unlock_share_entry_fsp(fsp);
-                       return NT_STATUS_ACCESS_DENIED;
-               }
+       if (fsp->is_directory || fsp->is_stat)
+               return NT_STATUS_OK;
 
-               /*
-                * Release the lock.
-                */
+       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_internal: failed to change delete on close flag for file %s\n",
+                       fsp->fsp_name ));
                unlock_share_entry_fsp(fsp);
-
-               /*
-                * Go through all files we have open on the same device and
-                * inode (hanging off the same hash bucket) and set the DELETE_ON_CLOSE_FLAG.
-                * Other smbd's that have this file open will look in the share_mode on close.
-                * take care of this (rare) case in close_file(). See the comment there.
-                * NB. JRA. We don't really need to do this anymore - all should be taken
-                * care of in the share_mode changes in the tdb.
-                */
-
-               for(iterate_fsp = file_find_di_first(fsp->dev, fsp->inode);
-                               iterate_fsp; iterate_fsp = file_find_di_next(iterate_fsp))
-                                               fsp->delete_on_close = delete_on_close;
-
-               /*
-                * Set the delete on close flag in the fsp.
-                */
-               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 ));
-
+               return NT_STATUS_ACCESS_DENIED;
        }
 
+       unlock_share_entry_fsp(fsp);
        return NT_STATUS_OK;
 }
 
@@ -2192,7 +2366,7 @@ static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in
                pstrcpy(link_dest, "./");
        }
                
-       if (conn->vfs_ops.realpath(conn,link_dest,resolved_name) == NULL)
+       if (SMB_VFS_REALPATH(conn,link_dest,resolved_name) == NULL)
                return -1;
 
        pstrcpy(link_dest, resolved_name);
@@ -2243,7 +2417,13 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
        gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
        mode_t unixmode = 0;
 
+       if (!params)
+               return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+
        if (tran_call == TRANSACT2_SETFILEINFO) {
+               if (total_params < 4)
+                       return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
                fsp = file_fsp(params,0);
                info_level = SVAL(params,2);    
 
@@ -2283,7 +2463,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                        pstrcpy(fname, fsp->fsp_name);
                        fd = fsp->fd;
 
-                       if (vfs_fstat(fsp,fd,&sbuf) != 0) {
+                       if (SMB_VFS_FSTAT(fsp,fd,&sbuf) != 0) {
                                DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
                                return(UNIXERROR(ERRDOS,ERRbadfid));
                        }
@@ -2475,7 +2655,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                                        if (new_fsp == NULL)
                                                return(UNIXERROR(ERRDOS,ERRbadpath));
                                        ret = vfs_allocate_file_space(new_fsp, allocation_size);
-                                       if (vfs_fstat(new_fsp,new_fsp->fd,&new_sbuf) != 0) {
+                                       if (SMB_VFS_FSTAT(new_fsp,new_fsp->fd,&new_sbuf) != 0) {
                                                DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",
                                                                        new_fsp->fnum, strerror(errno)));
                                                ret = -1;
@@ -2483,7 +2663,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
                                        close_file(new_fsp,True);
                                } else {
                                        ret = vfs_allocate_file_space(fsp, allocation_size);
-                                       if (vfs_fstat(fsp,fd,&new_sbuf) != 0) {
+                                       if (SMB_VFS_FSTAT(fsp,fd,&new_sbuf) != 0) {
                                                DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",
                                                                        fsp->fnum, strerror(errno)));
                                                ret = -1;
@@ -2533,6 +2713,11 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
 
                        status = set_delete_on_close_internal(fsp, delete_on_close);
  
+                       if (NT_STATUS_V(status) !=  NT_STATUS_V(NT_STATUS_OK))
+                               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);
 
@@ -2618,7 +2803,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
 0%o for file %s\n", (double)dev, unixmode, fname ));
 
                                /* Ok - do the mknod. */
-                               if (conn->vfs_ops.mknod(conn,dos_to_unix_static(fname), unixmode, dev) != 0)
+                               if (SMB_VFS_MKNOD(conn,dos_to_unix_static(fname), unixmode, dev) != 0)
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
 
                                inherit_access_acl(conn, fname, unixmode);
@@ -2637,7 +2822,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        if (raw_unixmode != SMB_MODE_NO_CHANGE) {
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n",
                                        (unsigned int)unixmode, fname ));
-                               if (vfs_chmod(conn,fname,unixmode) != 0)
+                               if (SMB_VFS_CHMOD(conn,fname,unixmode) != 0)
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                        }
 
@@ -2648,7 +2833,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (sbuf.st_uid != set_owner)) {
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n",
                                        (unsigned int)set_owner, fname ));
-                               if (vfs_chown(conn,fname,set_owner, (gid_t)-1) != 0)
+                               if (SMB_VFS_CHOWN(conn,fname,set_owner, (gid_t)-1) != 0)
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                        }
 
@@ -2659,7 +2844,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (sbuf.st_gid != set_grp)) {
                                DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n",
                                        (unsigned int)set_owner, fname ));
-                               if (vfs_chown(conn,fname,(uid_t)-1, set_grp) != 0)
+                               if (SMB_VFS_CHOWN(conn,fname,(uid_t)-1, set_grp) != 0)
                                        return(UNIXERROR(ERRDOS,ERRnoaccess));
                        }
                        break;
@@ -2686,7 +2871,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
                                fname, link_dest ));
 
-                       if (conn->vfs_ops.symlink(conn,link_dest,fname) != 0)
+                       if (SMB_VFS_SYMLINK(conn,link_dest,fname) != 0)
                                return(UNIXERROR(ERRDOS,ERRnoaccess));
                        SSVAL(params,0,0);
                        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
@@ -2711,7 +2896,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
                        DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
                                fname, link_dest ));
 
-                       if (conn->vfs_ops.link(conn,link_dest,fname) != 0)
+                       if (SMB_VFS_LINK(conn,link_dest,fname) != 0)
                                return(UNIXERROR(ERRDOS,ERRnoaccess));
                        SSVAL(params,0,0);
                        send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
@@ -2863,7 +3048,7 @@ static int call_trans2mkdir(connection_struct *conn,
 
        unix_convert(directory,conn,0,&bad_path,&sbuf);
        if (check_name(directory,conn))
-               ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
+               ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
   
        if(ret < 0) {
                DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
@@ -3008,8 +3193,6 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf,
        
        if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
                        (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
-               uint16 rap_jobid;
-
                pdata = Realloc(*ppdata, 32);
                if(pdata == NULL)
                        return ERROR_DOS(ERRDOS,ERRnomem);
@@ -3018,8 +3201,7 @@ static int call_trans2ioctl(connection_struct *conn, char* inbuf,
                /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
                        CAN ACCEPT THIS IN UNICODE. JRA. */
 
-               rap_jobid = pjobid_to_rap(SNUM(fsp->conn), fsp->print_jobid);                     /* Job number */
-               SSVAL(pdata,0,rap_jobid);                     /* Job number */
+               SSVAL(pdata,0,fsp->rap_print_jobid);                     /* Job number */
                srvstr_push( outbuf, pdata + 2, global_myname(), 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
                srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */
                send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32);
@@ -3114,7 +3296,7 @@ int reply_trans2(connection_struct *conn,
        unsigned int suwcnt = SVAL(inbuf, smb_suwcnt);
        unsigned int tran_call = SVAL(inbuf, smb_setup0);
        char *params = NULL, *data = NULL;
-       int num_params, num_params_sofar, num_data, num_data_sofar;
+       unsigned int num_params, num_params_sofar, num_data, num_data_sofar;
        START_PROFILE(SMBtrans2);
 
        if(global_oplock_break && (tran_call == TRANSACT2_OPEN)) {
@@ -3153,10 +3335,10 @@ int reply_trans2(connection_struct *conn,
                                (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
                        DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
                } else {
-                       DEBUG(2,("Invalid smb_sucnt in trans2 call(%d)\n",suwcnt));
+                       DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",suwcnt));
                        DEBUG(2,("Transaction is %d\n",tran_call));
                        END_PROFILE(SMBtrans2);
-                       return ERROR_DOS(ERRSRV,ERRerror);
+                       ERROR_DOS(ERRDOS,ERRinvalidparam);
                }
        }
     
@@ -3182,10 +3364,22 @@ int reply_trans2(connection_struct *conn,
        if (num_params > total_params || num_data > total_data)
                exit_server("invalid params in reply_trans2");
 
-       if(params)
-               memcpy( params, smb_base(inbuf) + SVAL(inbuf, smb_psoff), num_params);
-       if(data)
-               memcpy( data, smb_base(inbuf) + SVAL(inbuf, smb_dsoff), num_data);
+       if(params) {
+               unsigned int psoff = SVAL(inbuf, smb_psoff);
+               if ((psoff + num_params < psoff) || (psoff + num_params < num_params))
+                       goto bad_param;
+               if (smb_base(inbuf) + psoff + num_params > inbuf + length)
+                       goto bad_param;
+               memcpy( params, smb_base(inbuf) + psoff, num_params);
+       }
+       if(data) {
+               unsigned int dsoff = SVAL(inbuf, smb_dsoff);
+               if ((dsoff + num_data < dsoff) || (dsoff + num_data < num_data))
+                       goto bad_param;
+               if (smb_base(inbuf) + dsoff + num_data > inbuf + length)
+                       goto bad_param;
+               memcpy( data, smb_base(inbuf) + dsoff, num_data);
+       }
 
        if(num_data_sofar < total_data || num_params_sofar < total_params)  {
                /* We need to send an interim response then receive the rest
@@ -3197,6 +3391,10 @@ int reply_trans2(connection_struct *conn,
                while (num_data_sofar < total_data || 
                       num_params_sofar < total_params) {
                        BOOL ret;
+                       unsigned int param_disp;
+                       unsigned int param_off;
+                       unsigned int data_disp;
+                       unsigned int data_off;
 
                        ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
                        
@@ -3208,25 +3406,55 @@ int reply_trans2(connection_struct *conn,
                                else
                                        DEBUG(0,("reply_trans2: %s in getting secondary trans2 response.\n",
                                                 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
-                               SAFE_FREE(params);
-                               SAFE_FREE(data);
-                               END_PROFILE(SMBtrans2);
-                               return ERROR_DOS(ERRSRV,ERRerror);
+                               goto bad_param;
                        }
       
                        /* Revise total_params and total_data in case
                            they have changed downwards */
-                       total_params = SVAL(inbuf, smb_tpscnt);
-                       total_data = SVAL(inbuf, smb_tdscnt);
-                       num_params_sofar += (num_params = SVAL(inbuf,smb_spscnt));
-                       num_data_sofar += ( num_data = SVAL(inbuf, smb_sdscnt));
+                       if (SVAL(inbuf, smb_tpscnt) < total_params)
+                               total_params = SVAL(inbuf, smb_tpscnt);
+                       if (SVAL(inbuf, smb_tdscnt) < total_data)
+                               total_data = SVAL(inbuf, smb_tdscnt);
+
+                       num_params = SVAL(inbuf,smb_spscnt);
+                       param_off = SVAL(inbuf, smb_spsoff);
+                       param_disp = SVAL(inbuf, smb_spsdisp);
+                       num_params_sofar += num_params;
+
+                       num_data = SVAL(inbuf, smb_sdscnt);
+                       data_off = SVAL(inbuf, smb_sdsoff);
+                       data_disp = SVAL(inbuf, smb_sdsdisp);
+                       num_data_sofar += num_data;
+
                        if (num_params_sofar > total_params || num_data_sofar > total_data)
-                               exit_server("data overflow in trans2");
+                               goto bad_param;
                        
-                       memcpy( &params[ SVAL(inbuf, smb_spsdisp)], 
-                               smb_base(inbuf) + SVAL(inbuf, smb_spsoff), num_params);
-                       memcpy( &data[SVAL(inbuf, smb_sdsdisp)],
-                               smb_base(inbuf)+ SVAL(inbuf, smb_sdsoff), num_data);
+                       if (num_params) {
+                               if (param_disp + num_params >= total_params)
+                                       goto bad_param;
+                               if ((param_disp + num_params < param_disp) ||
+                                               (param_disp + num_params < num_params))
+                                       goto bad_param;
+                               if (smb_base(inbuf) + param_off + num_params >= inbuf + bufsize)
+                                       goto bad_param;
+                               if (params + param_disp < params)
+                                       goto bad_param;
+
+                               memcpy( &params[param_disp], smb_base(inbuf) + param_off, num_params);
+                       }
+                       if (num_data) {
+                               if (data_disp + num_data >= total_data)
+                                       goto bad_param;
+                               if ((data_disp + num_data < data_disp) ||
+                                               (data_disp + num_data < num_data))
+                                       goto bad_param;
+                               if (smb_base(inbuf) + data_off + num_data >= inbuf + bufsize)
+                                       goto bad_param;
+                               if (data + data_disp < data)
+                                       goto bad_param;
+
+                               memcpy( &data[data_disp], smb_base(inbuf) + data_off, num_data);
+                       }
                }
        }
        
@@ -3264,13 +3492,14 @@ int reply_trans2(connection_struct *conn,
                END_PROFILE_NESTED(Trans2_qfsinfo);
            break;
 
+#ifdef WITH_QUOTAS
        case TRANSACT2_SETFSINFO:
                START_PROFILE_NESTED(Trans2_setfsinfo);
                outsize = call_trans2setfsinfo(conn, inbuf, outbuf, length, bufsize, 
                                          &params, total_params, &data, total_data);
                END_PROFILE_NESTED(Trans2_setfsinfo);
                break;
-
+#endif
        case TRANSACT2_QPATHINFO:
        case TRANSACT2_QFILEINFO:
                START_PROFILE_NESTED(Trans2_qpathinfo);
@@ -3340,4 +3569,11 @@ int reply_trans2(connection_struct *conn,
        return outsize; /* If a correct response was needed the
                           call_trans2xxx calls have already sent
                           it. If outsize != -1 then it is returning */
+
+  bad_param:
+
+       SAFE_FREE(params);
+       SAFE_FREE(data);
+       END_PROFILE(SMBtrans2);
+       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 }