smbd/trans2.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    SMB transaction2 handling
00004    Copyright (C) Jeremy Allison                 1994-2007
00005    Copyright (C) Stefan (metze) Metzmacher      2003
00006    Copyright (C) Volker Lendecke                2005
00007    Copyright (C) Steve French                   2005
00008    Copyright (C) James Peach                    2007
00009 
00010    Extensively modified by Andrew Tridgell, 1995
00011 
00012    This program is free software; you can redistribute it and/or modify
00013    it under the terms of the GNU General Public License as published by
00014    the Free Software Foundation; either version 2 of the License, or
00015    (at your option) any later version.
00016    
00017    This program is distributed in the hope that it will be useful,
00018    but WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020    GNU General Public License for more details.
00021    
00022    You should have received a copy of the GNU General Public License
00023    along with this program; if not, write to the Free Software
00024    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 */
00026 
00027 #include "includes.h"
00028 
00029 extern int max_send;
00030 extern enum protocol_types Protocol;
00031 extern int smb_read_error;
00032 extern uint32 global_client_caps;
00033 extern struct current_user current_user;
00034 
00035 #define get_file_size(sbuf) ((sbuf).st_size)
00036 #define DIR_ENTRY_SAFETY_MARGIN 4096
00037 
00038 static char *store_file_unix_basic(connection_struct *conn,
00039                                 char *pdata,
00040                                 files_struct *fsp,
00041                                 const SMB_STRUCT_STAT *psbuf);
00042 
00043 static char *store_file_unix_basic_info2(connection_struct *conn,
00044                                 char *pdata,
00045                                 files_struct *fsp,
00046                                 const SMB_STRUCT_STAT *psbuf);
00047 
00048 /********************************************************************
00049  Roundup a value to the nearest allocation roundup size boundary.
00050  Only do this for Windows clients.
00051 ********************************************************************/
00052 
00053 SMB_BIG_UINT smb_roundup(connection_struct *conn, SMB_BIG_UINT val)
00054 {
00055         SMB_BIG_UINT rval = lp_allocation_roundup_size(SNUM(conn));
00056 
00057         /* Only roundup for Windows clients. */
00058         enum remote_arch_types ra_type = get_remote_arch();
00059         if (rval && (ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
00060                 val = SMB_ROUNDUP(val,rval);
00061         }
00062         return val;
00063 }
00064 
00065 /********************************************************************
00066  Given a stat buffer return the allocated size on disk, taking into
00067  account sparse files.
00068 ********************************************************************/
00069 
00070 SMB_BIG_UINT get_allocation_size(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *sbuf)
00071 {
00072         SMB_BIG_UINT ret;
00073 
00074         if(S_ISDIR(sbuf->st_mode)) {
00075                 return 0;
00076         }
00077 
00078 #if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
00079         ret = (SMB_BIG_UINT)STAT_ST_BLOCKSIZE * (SMB_BIG_UINT)sbuf->st_blocks;
00080 #else
00081         ret = (SMB_BIG_UINT)get_file_size(*sbuf);
00082 #endif
00083 
00084         if (fsp && fsp->initial_allocation_size)
00085                 ret = MAX(ret,fsp->initial_allocation_size);
00086 
00087         return smb_roundup(conn, ret);
00088 }
00089 
00090 /****************************************************************************
00091  Utility functions for dealing with extended attributes.
00092 ****************************************************************************/
00093 
00094 static const char *prohibited_ea_names[] = {
00095         SAMBA_POSIX_INHERITANCE_EA_NAME,
00096         SAMBA_XATTR_DOS_ATTRIB,
00097         NULL
00098 };
00099 
00100 /****************************************************************************
00101  Refuse to allow clients to overwrite our private xattrs.
00102 ****************************************************************************/
00103 
00104 static BOOL samba_private_attr_name(const char *unix_ea_name)
00105 {
00106         int i;
00107 
00108         for (i = 0; prohibited_ea_names[i]; i++) {
00109                 if (strequal( prohibited_ea_names[i], unix_ea_name))
00110                         return True;
00111         }
00112         return False;
00113 }
00114 
00115 /****************************************************************************
00116  Get one EA value. Fill in a struct ea_struct.
00117 ****************************************************************************/
00118 
00119 static BOOL get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
00120                                 const char *fname, char *ea_name, struct ea_struct *pea)
00121 {
00122         /* Get the value of this xattr. Max size is 64k. */
00123         size_t attr_size = 256;
00124         char *val = NULL;
00125         ssize_t sizeret;
00126 
00127  again:
00128 
00129         val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
00130         if (!val) {
00131                 return False;
00132         }
00133 
00134         if (fsp && fsp->fh->fd != -1) {
00135                 sizeret = SMB_VFS_FGETXATTR(fsp, fsp->fh->fd, ea_name, val, attr_size);
00136         } else {
00137                 sizeret = SMB_VFS_GETXATTR(conn, fname, ea_name, val, attr_size);
00138         }
00139 
00140         if (sizeret == -1 && errno == ERANGE && attr_size != 65536) {
00141                 attr_size = 65536;
00142                 goto again;
00143         }
00144 
00145         if (sizeret == -1) {
00146                 return False;
00147         }
00148 
00149         DEBUG(10,("get_ea_value: EA %s is of length %u: ", ea_name, (unsigned int)sizeret));
00150         dump_data(10, val, sizeret);
00151 
00152         pea->flags = 0;
00153         if (strnequal(ea_name, "user.", 5)) {
00154                 pea->name = &ea_name[5];
00155         } else {
00156                 pea->name = ea_name;
00157         }
00158         pea->value.data = (unsigned char *)val;
00159         pea->value.length = (size_t)sizeret;
00160         return True;
00161 }
00162 
00163 /****************************************************************************
00164  Return a linked list of the total EA's. Plus the total size
00165 ****************************************************************************/
00166 
00167 static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
00168                                         const char *fname, size_t *pea_total_len)
00169 {
00170         /* Get a list of all xattrs. Max namesize is 64k. */
00171         size_t ea_namelist_size = 1024;
00172         char *ea_namelist;
00173         char *p;
00174         ssize_t sizeret;
00175         int i;
00176         struct ea_list *ea_list_head = NULL;
00177 
00178         *pea_total_len = 0;
00179 
00180         if (!lp_ea_support(SNUM(conn))) {
00181                 return NULL;
00182         }
00183 
00184         for (i = 0, ea_namelist = TALLOC_ARRAY(mem_ctx, char, ea_namelist_size); i < 6;
00185              ea_namelist = TALLOC_REALLOC_ARRAY(mem_ctx, ea_namelist, char, ea_namelist_size), i++) {
00186 
00187                 if (!ea_namelist) {
00188                         return NULL;
00189                 }
00190 
00191                 if (fsp && fsp->fh->fd != -1) {
00192                         sizeret = SMB_VFS_FLISTXATTR(fsp, fsp->fh->fd, ea_namelist, ea_namelist_size);
00193                 } else {
00194                         sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, ea_namelist_size);
00195                 }
00196 
00197                 if (sizeret == -1 && errno == ERANGE) {
00198                         ea_namelist_size *= 2;
00199                 } else {
00200                         break;
00201                 }
00202         }
00203 
00204         if (sizeret == -1)
00205                 return NULL;
00206 
00207         DEBUG(10,("get_ea_list_from_file: ea_namelist size = %u\n", (unsigned int)sizeret ));
00208 
00209         if (sizeret) {
00210                 for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p) + 1) {
00211                         struct ea_list *listp;
00212 
00213                         if (strnequal(p, "system.", 7) || samba_private_attr_name(p))
00214                                 continue;
00215                 
00216                         listp = TALLOC_P(mem_ctx, struct ea_list);
00217                         if (!listp)
00218                                 return NULL;
00219 
00220                         if (!get_ea_value(mem_ctx, conn, fsp, fname, p, &listp->ea)) {
00221                                 return NULL;
00222                         }
00223 
00224                         {
00225                                 fstring dos_ea_name;
00226                                 push_ascii_fstring(dos_ea_name, listp->ea.name);
00227                                 *pea_total_len += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
00228                                 DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len = %u\n",
00229                                         (unsigned int)*pea_total_len, dos_ea_name,
00230                                         (unsigned int)listp->ea.value.length ));
00231                         }
00232                         DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
00233                 }
00234                 /* Add on 4 for total length. */
00235                 if (*pea_total_len) {
00236                         *pea_total_len += 4;
00237                 }
00238         }
00239 
00240         DEBUG(10,("get_ea_list_from_file: total_len = %u\n", (unsigned int)*pea_total_len));
00241         return ea_list_head;
00242 }
00243 
00244 /****************************************************************************
00245  Fill a qfilepathinfo buffer with EA's. Returns the length of the buffer
00246  that was filled.
00247 ****************************************************************************/
00248 
00249 static unsigned int fill_ea_buffer(TALLOC_CTX *mem_ctx, char *pdata, unsigned int total_data_size,
00250         connection_struct *conn, struct ea_list *ea_list)
00251 {
00252         unsigned int ret_data_size = 4;
00253         char *p = pdata;
00254 
00255         SMB_ASSERT(total_data_size >= 4);
00256 
00257         if (!lp_ea_support(SNUM(conn))) {
00258                 SIVAL(pdata,4,0);
00259                 return 4;
00260         }
00261 
00262         for (p = pdata + 4; ea_list; ea_list = ea_list->next) {
00263                 size_t dos_namelen;
00264                 fstring dos_ea_name;
00265                 push_ascii_fstring(dos_ea_name, ea_list->ea.name);
00266                 dos_namelen = strlen(dos_ea_name);
00267                 if (dos_namelen > 255 || dos_namelen == 0) {
00268                         break;
00269                 }
00270                 if (ea_list->ea.value.length > 65535) {
00271                         break;
00272                 }
00273                 if (4 + dos_namelen + 1 + ea_list->ea.value.length > total_data_size) {
00274                         break;
00275                 }
00276 
00277                 /* We know we have room. */
00278                 SCVAL(p,0,ea_list->ea.flags);
00279                 SCVAL(p,1,dos_namelen);
00280                 SSVAL(p,2,ea_list->ea.value.length);
00281                 fstrcpy(p+4, dos_ea_name);
00282                 memcpy( p + 4 + dos_namelen + 1, ea_list->ea.value.data, ea_list->ea.value.length);
00283 
00284                 total_data_size -= 4 + dos_namelen + 1 + ea_list->ea.value.length;
00285                 p += 4 + dos_namelen + 1 + ea_list->ea.value.length;
00286         }
00287 
00288         ret_data_size = PTR_DIFF(p, pdata);
00289         DEBUG(10,("fill_ea_buffer: data_size = %u\n", ret_data_size ));
00290         SIVAL(pdata,0,ret_data_size);
00291         return ret_data_size;
00292 }
00293 
00294 static unsigned int estimate_ea_size(connection_struct *conn, files_struct *fsp, const char *fname)
00295 {
00296         size_t total_ea_len = 0;
00297         TALLOC_CTX *mem_ctx = NULL;
00298 
00299         if (!lp_ea_support(SNUM(conn))) {
00300                 return 0;
00301         }
00302         mem_ctx = talloc_init("estimate_ea_size");
00303         (void)get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
00304         talloc_destroy(mem_ctx);
00305         return total_ea_len;
00306 }
00307 
00308 /****************************************************************************
00309  Ensure the EA name is case insensitive by matching any existing EA name.
00310 ****************************************************************************/
00311 
00312 static void canonicalize_ea_name(connection_struct *conn, files_struct *fsp, const char *fname, fstring unix_ea_name)
00313 {
00314         size_t total_ea_len;
00315         TALLOC_CTX *mem_ctx = talloc_init("canonicalize_ea_name");
00316         struct ea_list *ea_list = get_ea_list_from_file(mem_ctx, conn, fsp, fname, &total_ea_len);
00317 
00318         for (; ea_list; ea_list = ea_list->next) {
00319                 if (strequal(&unix_ea_name[5], ea_list->ea.name)) {
00320                         DEBUG(10,("canonicalize_ea_name: %s -> %s\n",
00321                                 &unix_ea_name[5], ea_list->ea.name));
00322                         safe_strcpy(&unix_ea_name[5], ea_list->ea.name, sizeof(fstring)-6);
00323                         break;
00324                 }
00325         }
00326         talloc_destroy(mem_ctx);
00327 }
00328 
00329 /****************************************************************************
00330  Set or delete an extended attribute.
00331 ****************************************************************************/
00332 
00333 NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, const char *fname, struct ea_list *ea_list)
00334 {
00335         if (!lp_ea_support(SNUM(conn))) {
00336                 return NT_STATUS_EAS_NOT_SUPPORTED;
00337         }
00338 
00339         for (;ea_list; ea_list = ea_list->next) {
00340                 int ret;
00341                 fstring unix_ea_name;
00342 
00343                 fstrcpy(unix_ea_name, "user."); /* All EA's must start with user. */
00344                 fstrcat(unix_ea_name, ea_list->ea.name);
00345 
00346                 canonicalize_ea_name(conn, fsp, fname, unix_ea_name);
00347 
00348                 DEBUG(10,("set_ea: ea_name %s ealen = %u\n", unix_ea_name, (unsigned int)ea_list->ea.value.length));
00349 
00350                 if (samba_private_attr_name(unix_ea_name)) {
00351                         DEBUG(10,("set_ea: ea name %s is a private Samba name.\n", unix_ea_name));
00352                         return NT_STATUS_ACCESS_DENIED;
00353                 }
00354 
00355                 if (ea_list->ea.value.length == 0) {
00356                         /* Remove the attribute. */
00357                         if (fsp && (fsp->fh->fd != -1)) {
00358                                 DEBUG(10,("set_ea: deleting ea name %s on file %s by file descriptor.\n",
00359                                         unix_ea_name, fsp->fsp_name));
00360                                 ret = SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->fd, unix_ea_name);
00361                         } else {
00362                                 DEBUG(10,("set_ea: deleting ea name %s on file %s.\n",
00363                                         unix_ea_name, fname));
00364                                 ret = SMB_VFS_REMOVEXATTR(conn, fname, unix_ea_name);
00365                         }
00366 #ifdef ENOATTR
00367                         /* Removing a non existent attribute always succeeds. */
00368                         if (ret == -1 && errno == ENOATTR) {
00369                                 DEBUG(10,("set_ea: deleting ea name %s didn't exist - succeeding by default.\n",
00370                                                 unix_ea_name));
00371                                 ret = 0;
00372                         }
00373 #endif
00374                 } else {
00375                         if (fsp && (fsp->fh->fd != -1)) {
00376                                 DEBUG(10,("set_ea: setting ea name %s on file %s by file descriptor.\n",
00377                                         unix_ea_name, fsp->fsp_name));
00378                                 ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->fd, unix_ea_name,
00379                                                         ea_list->ea.value.data, ea_list->ea.value.length, 0);
00380                         } else {
00381                                 DEBUG(10,("set_ea: setting ea name %s on file %s.\n",
00382                                         unix_ea_name, fname));
00383                                 ret = SMB_VFS_SETXATTR(conn, fname, unix_ea_name,
00384                                                         ea_list->ea.value.data, ea_list->ea.value.length, 0);
00385                         }
00386                 }
00387 
00388                 if (ret == -1) {
00389 #ifdef ENOTSUP
00390                         if (errno == ENOTSUP) {
00391                                 return NT_STATUS_EAS_NOT_SUPPORTED;
00392                         }
00393 #endif
00394                         return map_nt_error_from_unix(errno);
00395                 }
00396 
00397         }
00398         return NT_STATUS_OK;
00399 }
00400 /****************************************************************************
00401  Read a list of EA names from an incoming data buffer. Create an ea_list with them.
00402 ****************************************************************************/
00403 
00404 static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
00405 {
00406         struct ea_list *ea_list_head = NULL;
00407         size_t offset = 0;
00408 
00409         while (offset + 2 < data_size) {
00410                 struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
00411                 unsigned int namelen = CVAL(pdata,offset);
00412 
00413                 offset++; /* Go past the namelen byte. */
00414 
00415                 /* integer wrap paranioa. */
00416                 if ((offset + namelen < offset) || (offset + namelen < namelen) ||
00417                                 (offset > data_size) || (namelen > data_size) ||
00418                                 (offset + namelen >= data_size)) {
00419                         break;
00420                 }
00421                 /* Ensure the name is null terminated. */
00422                 if (pdata[offset + namelen] != '\0') {
00423                         return NULL;
00424                 }
00425                 pull_ascii_talloc(ctx, &eal->ea.name, &pdata[offset]);
00426                 if (!eal->ea.name) {
00427                         return NULL;
00428                 }
00429 
00430                 offset += (namelen + 1); /* Go past the name + terminating zero. */
00431                 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
00432                 DEBUG(10,("read_ea_name_list: read ea name %s\n", eal->ea.name));
00433         }
00434 
00435         return ea_list_head;
00436 }
00437 
00438 /****************************************************************************
00439  Read one EA list entry from the buffer.
00440 ****************************************************************************/
00441 
00442 struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used)
00443 {
00444         struct ea_list *eal = TALLOC_ZERO_P(ctx, struct ea_list);
00445         uint16 val_len;
00446         unsigned int namelen;
00447 
00448         if (!eal) {
00449                 return NULL;
00450         }
00451 
00452         if (data_size < 6) {
00453                 return NULL;
00454         }
00455 
00456         eal->ea.flags = CVAL(pdata,0);
00457         namelen = CVAL(pdata,1);
00458         val_len = SVAL(pdata,2);
00459 
00460         if (4 + namelen + 1 + val_len > data_size) {
00461                 return NULL;
00462         }
00463 
00464         /* Ensure the name is null terminated. */
00465         if (pdata[namelen + 4] != '\0') {
00466                 return NULL;
00467         }
00468         pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4);
00469         if (!eal->ea.name) {
00470                 return NULL;
00471         }
00472 
00473         eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1);
00474         if (!eal->ea.value.data) {
00475                 return NULL;
00476         }
00477 
00478         memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len);
00479 
00480         /* Ensure we're null terminated just in case we print the value. */
00481         eal->ea.value.data[val_len] = '\0';
00482         /* But don't count the null. */
00483         eal->ea.value.length--;
00484 
00485         if (pbytes_used) {
00486                 *pbytes_used = 4 + namelen + 1 + val_len;
00487         }
00488 
00489         DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name));
00490         dump_data(10, (const char *)eal->ea.value.data, eal->ea.value.length);
00491 
00492         return eal;
00493 }
00494 
00495 /****************************************************************************
00496  Read a list of EA names and data from an incoming data buffer. Create an ea_list with them.
00497 ****************************************************************************/
00498 
00499 static struct ea_list *read_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size)
00500 {
00501         struct ea_list *ea_list_head = NULL;
00502         size_t offset = 0;
00503         size_t bytes_used = 0;
00504 
00505         while (offset < data_size) {
00506                 struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset, data_size - offset, &bytes_used);
00507 
00508                 if (!eal) {
00509                         return NULL;
00510                 }
00511 
00512                 DLIST_ADD_END(ea_list_head, eal, struct ea_list *);
00513                 offset += bytes_used;
00514         }
00515 
00516         return ea_list_head;
00517 }
00518 
00519 /****************************************************************************
00520  Count the total EA size needed.
00521 ****************************************************************************/
00522 
00523 static size_t ea_list_size(struct ea_list *ealist)
00524 {
00525         fstring dos_ea_name;
00526         struct ea_list *listp;
00527         size_t ret = 0;
00528 
00529         for (listp = ealist; listp; listp = listp->next) {
00530                 push_ascii_fstring(dos_ea_name, listp->ea.name);
00531                 ret += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
00532         }
00533         /* Add on 4 for total length. */
00534         if (ret) {
00535                 ret += 4;
00536         }
00537 
00538         return ret;
00539 }
00540 
00541 /****************************************************************************
00542  Return a union of EA's from a file list and a list of names.
00543  The TALLOC context for the two lists *MUST* be identical as we steal
00544  memory from one list to add to another. JRA.
00545 ****************************************************************************/
00546 
00547 static struct ea_list *ea_list_union(struct ea_list *name_list, struct ea_list *file_list, size_t *total_ea_len)
00548 {
00549         struct ea_list *nlistp, *flistp;
00550 
00551         for (nlistp = name_list; nlistp; nlistp = nlistp->next) {
00552                 for (flistp = file_list; flistp; flistp = flistp->next) {
00553                         if (strequal(nlistp->ea.name, flistp->ea.name)) {
00554                                 break;
00555                         }
00556                 }
00557 
00558                 if (flistp) {
00559                         /* Copy the data from this entry. */
00560                         nlistp->ea.flags = flistp->ea.flags;
00561                         nlistp->ea.value = flistp->ea.value;
00562                 } else {
00563                         /* Null entry. */
00564                         nlistp->ea.flags = 0;
00565                         ZERO_STRUCT(nlistp->ea.value);
00566                 }
00567         }
00568 
00569         *total_ea_len = ea_list_size(name_list);
00570         return name_list;
00571 }
00572 
00573 /****************************************************************************
00574   Send the required number of replies back.
00575   We assume all fields other than the data fields are
00576   set correctly for the type of call.
00577   HACK ! Always assumes smb_setup field is zero.
00578 ****************************************************************************/
00579 
00580 int send_trans2_replies(char *outbuf,
00581                         int bufsize,
00582                         const char *params, 
00583                         int paramsize,
00584                         const char *pdata,
00585                         int datasize,
00586                         int max_data_bytes)
00587 {
00588         /* As we are using a protocol > LANMAN1 then the max_send
00589          variable must have been set in the sessetupX call.
00590          This takes precedence over the max_xmit field in the
00591          global struct. These different max_xmit variables should
00592          be merged as this is now too confusing */
00593 
00594         int data_to_send = datasize;
00595         int params_to_send = paramsize;
00596         int useable_space;
00597         const char *pp = params;
00598         const char *pd = pdata;
00599         int params_sent_thistime, data_sent_thistime, total_sent_thistime;
00600         int alignment_offset = 1; /* JRA. This used to be 3. Set to 1 to make netmon parse ok. */
00601         int data_alignment_offset = 0;
00602 
00603         /* Initially set the wcnt area to be 10 - this is true for all trans2 replies */
00604         
00605         set_message(outbuf,10,0,True);
00606 
00607         /* Modify the data_to_send and datasize and set the error if
00608            we're trying to send more than max_data_bytes. We still send
00609            the part of the packet(s) that fit. Strange, but needed
00610            for OS/2. */
00611 
00612         if (max_data_bytes > 0 && datasize > max_data_bytes) {
00613                 DEBUG(5,("send_trans2_replies: max_data_bytes %d exceeded by data %d\n",
00614                         max_data_bytes, datasize ));
00615                 datasize = data_to_send = max_data_bytes;
00616                 error_packet_set(outbuf,ERRDOS,ERRbufferoverflow,STATUS_BUFFER_OVERFLOW,__LINE__,__FILE__);
00617         }
00618 
00619         /* If there genuinely are no parameters or data to send just send the empty packet */
00620 
00621         if(params_to_send == 0 && data_to_send == 0) {
00622                 show_msg(outbuf);
00623                 if (!send_smb(smbd_server_fd(),outbuf))
00624                         exit_server_cleanly("send_trans2_replies: send_smb failed.");
00625                 return 0;
00626         }
00627 
00628         /* When sending params and data ensure that both are nicely aligned */
00629         /* Only do this alignment when there is also data to send - else
00630                 can cause NT redirector problems. */
00631 
00632         if (((params_to_send % 4) != 0) && (data_to_send != 0))
00633                 data_alignment_offset = 4 - (params_to_send % 4);
00634 
00635         /* Space is bufsize minus Netbios over TCP header minus SMB header */
00636         /* The alignment_offset is to align the param bytes on an even byte
00637                 boundary. NT 4.0 Beta needs this to work correctly. */
00638 
00639         useable_space = bufsize - ((smb_buf(outbuf)+ alignment_offset+data_alignment_offset) - outbuf);
00640 
00641         /* useable_space can never be more than max_send minus the alignment offset. */
00642 
00643         useable_space = MIN(useable_space, max_send - (alignment_offset+data_alignment_offset));
00644 
00645         while (params_to_send || data_to_send) {
00646                 /* Calculate whether we will totally or partially fill this packet */
00647 
00648                 total_sent_thistime = params_to_send + data_to_send + alignment_offset + data_alignment_offset;
00649 
00650                 /* We can never send more than useable_space */
00651                 /*
00652                  * Note that 'useable_space' does not include the alignment offsets,
00653                  * but we must include the alignment offsets in the calculation of
00654                  * the length of the data we send over the wire, as the alignment offsets
00655                  * are sent here. Fix from Marc_Jacobsen@hp.com.
00656                  */
00657 
00658                 total_sent_thistime = MIN(total_sent_thistime, useable_space+ alignment_offset + data_alignment_offset);
00659 
00660                 set_message(outbuf, 10, total_sent_thistime, True);
00661 
00662                 /* Set total params and data to be sent */
00663                 SSVAL(outbuf,smb_tprcnt,paramsize);
00664                 SSVAL(outbuf,smb_tdrcnt,datasize);
00665 
00666                 /* Calculate how many parameters and data we can fit into
00667                  * this packet. Parameters get precedence
00668                  */
00669 
00670                 params_sent_thistime = MIN(params_to_send,useable_space);
00671                 data_sent_thistime = useable_space - params_sent_thistime;
00672                 data_sent_thistime = MIN(data_sent_thistime,data_to_send);
00673 
00674                 SSVAL(outbuf,smb_prcnt, params_sent_thistime);
00675 
00676                 /* smb_proff is the offset from the start of the SMB header to the
00677                         parameter bytes, however the first 4 bytes of outbuf are
00678                         the Netbios over TCP header. Thus use smb_base() to subtract
00679                         them from the calculation */
00680 
00681                 SSVAL(outbuf,smb_proff,((smb_buf(outbuf)+alignment_offset) - smb_base(outbuf)));
00682 
00683                 if(params_sent_thistime == 0)
00684                         SSVAL(outbuf,smb_prdisp,0);
00685                 else
00686                         /* Absolute displacement of param bytes sent in this packet */
00687                         SSVAL(outbuf,smb_prdisp,pp - params);
00688 
00689                 SSVAL(outbuf,smb_drcnt, data_sent_thistime);
00690                 if(data_sent_thistime == 0) {
00691                         SSVAL(outbuf,smb_droff,0);
00692                         SSVAL(outbuf,smb_drdisp, 0);
00693                 } else {
00694                         /* The offset of the data bytes is the offset of the
00695                                 parameter bytes plus the number of parameters being sent this time */
00696                         SSVAL(outbuf,smb_droff,((smb_buf(outbuf)+alignment_offset) - 
00697                                 smb_base(outbuf)) + params_sent_thistime + data_alignment_offset);
00698                         SSVAL(outbuf,smb_drdisp, pd - pdata);
00699                 }
00700 
00701                 /* Copy the param bytes into the packet */
00702 
00703                 if(params_sent_thistime)
00704                         memcpy((smb_buf(outbuf)+alignment_offset),pp,params_sent_thistime);
00705 
00706                 /* Copy in the data bytes */
00707                 if(data_sent_thistime)
00708                         memcpy(smb_buf(outbuf)+alignment_offset+params_sent_thistime+
00709                                 data_alignment_offset,pd,data_sent_thistime);
00710 
00711                 DEBUG(9,("t2_rep: params_sent_thistime = %d, data_sent_thistime = %d, useable_space = %d\n",
00712                         params_sent_thistime, data_sent_thistime, useable_space));
00713                 DEBUG(9,("t2_rep: params_to_send = %d, data_to_send = %d, paramsize = %d, datasize = %d\n",
00714                         params_to_send, data_to_send, paramsize, datasize));
00715 
00716                 /* Send the packet */
00717                 show_msg(outbuf);
00718                 if (!send_smb(smbd_server_fd(),outbuf))
00719                         exit_server_cleanly("send_trans2_replies: send_smb failed.");
00720 
00721                 pp += params_sent_thistime;
00722                 pd += data_sent_thistime;
00723 
00724                 params_to_send -= params_sent_thistime;
00725                 data_to_send -= data_sent_thistime;
00726 
00727                 /* Sanity check */
00728                 if(params_to_send < 0 || data_to_send < 0) {
00729                         DEBUG(0,("send_trans2_replies failed sanity check pts = %d, dts = %d\n!!!",
00730                                 params_to_send, data_to_send));
00731                         return -1;
00732                 }
00733         }
00734 
00735         return 0;
00736 }
00737 
00738 /****************************************************************************
00739  Reply to a TRANSACT2_OPEN.
00740 ****************************************************************************/
00741 
00742 static int call_trans2open(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
00743                                 char **pparams, int total_params, char **ppdata, int total_data,
00744                                 unsigned int max_data_bytes)
00745 {
00746         char *params = *pparams;
00747         char *pdata = *ppdata;
00748         int deny_mode;
00749         int32 open_attr;
00750         BOOL oplock_request;
00751 #if 0
00752         BOOL return_additional_info;
00753         int16 open_sattr;
00754         time_t open_time;
00755 #endif
00756         int open_ofun;
00757         uint32 open_size;
00758         char *pname;
00759         pstring fname;
00760         SMB_OFF_T size=0;
00761         int fattr=0,mtime=0;
00762         SMB_INO_T inode = 0;
00763         SMB_STRUCT_STAT sbuf;
00764         int smb_action = 0;
00765         files_struct *fsp;
00766         struct ea_list *ea_list = NULL;
00767         uint16 flags = 0;
00768         NTSTATUS status;
00769         uint32 access_mask;
00770         uint32 share_mode;
00771         uint32 create_disposition;
00772         uint32 create_options = 0;
00773 
00774         /*
00775          * Ensure we have enough parameters to perform the operation.
00776          */
00777 
00778         if (total_params < 29) {
00779                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
00780         }
00781 
00782         flags = SVAL(params, 0);
00783         deny_mode = SVAL(params, 2);
00784         open_attr = SVAL(params,6);
00785         oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
00786         if (oplock_request) {
00787                 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
00788         }
00789 
00790 #if 0
00791         return_additional_info = BITSETW(params,0);
00792         open_sattr = SVAL(params, 4);
00793         open_time = make_unix_date3(params+8);
00794 #endif
00795         open_ofun = SVAL(params,12);
00796         open_size = IVAL(params,14);
00797         pname = &params[28];
00798 
00799         if (IS_IPC(conn)) {
00800                 return(ERROR_DOS(ERRSRV,ERRaccess));
00801         }
00802 
00803         srvstr_get_path(inbuf, fname, pname, sizeof(fname), total_params - 28, STR_TERMINATE, &status);
00804         if (!NT_STATUS_IS_OK(status)) {
00805                 return ERROR_NT(status);
00806         }
00807 
00808         DEBUG(3,("call_trans2open %s deny_mode=0x%x attr=%d ofun=0x%x size=%d\n",
00809                 fname, (unsigned int)deny_mode, (unsigned int)open_attr,
00810                 (unsigned int)open_ofun, open_size));
00811 
00812         /* XXXX we need to handle passed times, sattr and flags */
00813 
00814         status = unix_convert(conn, fname, False, NULL, &sbuf);
00815         if (!NT_STATUS_IS_OK(status)) {
00816                 return ERROR_NT(status);
00817         }
00818     
00819         status = check_name(conn, fname);
00820         if (!NT_STATUS_IS_OK(status)) {
00821                 return ERROR_NT(status);
00822         }
00823 
00824         if (open_ofun == 0) {
00825                 return ERROR_NT(NT_STATUS_OBJECT_NAME_COLLISION);
00826         }
00827 
00828         if (!map_open_params_to_ntcreate(fname, deny_mode, open_ofun,
00829                                 &access_mask,
00830                                 &share_mode,
00831                                 &create_disposition,
00832                                 &create_options)) {
00833                 return ERROR_DOS(ERRDOS, ERRbadaccess);
00834         }
00835 
00836         /* Any data in this call is an EA list. */
00837         if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
00838                 return ERROR_NT(NT_STATUS_EAS_NOT_SUPPORTED);
00839         }
00840 
00841         if (total_data != 4) {
00842                 if (total_data < 10) {
00843                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
00844                 }
00845 
00846                 if (IVAL(pdata,0) > total_data) {
00847                         DEBUG(10,("call_trans2open: bad total data size (%u) > %u\n",
00848                                 IVAL(pdata,0), (unsigned int)total_data));
00849                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
00850                 }
00851 
00852                 ea_list = read_ea_list(tmp_talloc_ctx(), pdata + 4,
00853                                        total_data - 4);
00854                 if (!ea_list) {
00855                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
00856                 }
00857         } else if (IVAL(pdata,0) != 4) {
00858                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
00859         }
00860 
00861         status = open_file_ntcreate(conn,fname,&sbuf,
00862                 access_mask,
00863                 share_mode,
00864                 create_disposition,
00865                 create_options,
00866                 open_attr,
00867                 oplock_request,
00868                 &smb_action, &fsp);
00869 
00870         if (!NT_STATUS_IS_OK(status)) {
00871                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
00872                         /* We have re-scheduled this call. */
00873                         return -1;
00874                 }
00875                 return ERROR_OPEN(status);
00876         }
00877 
00878         size = get_file_size(sbuf);
00879         fattr = dos_mode(conn,fname,&sbuf);
00880         mtime = sbuf.st_mtime;
00881         inode = sbuf.st_ino;
00882         if (fattr & aDIR) {
00883                 close_file(fsp,ERROR_CLOSE);
00884                 return(ERROR_DOS(ERRDOS,ERRnoaccess));
00885         }
00886 
00887         /* Save the requested allocation size. */
00888         /* Allocate space for the file if a size hint is supplied */
00889         if ((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) {
00890                 SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)open_size;
00891                 if (allocation_size && (allocation_size > (SMB_BIG_UINT)size)) {
00892                         fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
00893                         if (fsp->is_directory) {
00894                                 close_file(fsp,ERROR_CLOSE);
00895                                 /* Can't set allocation size on a directory. */
00896                                 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
00897                         }
00898                         if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
00899                                 close_file(fsp,ERROR_CLOSE);
00900                                 return ERROR_NT(NT_STATUS_DISK_FULL);
00901                         }
00902 
00903                         /* Adjust size here to return the right size in the reply.
00904                            Windows does it this way. */
00905                         size = fsp->initial_allocation_size;
00906                 } else {
00907                         fsp->initial_allocation_size = smb_roundup(fsp->conn,(SMB_BIG_UINT)size);
00908                 }
00909         }
00910 
00911         if (ea_list && smb_action == FILE_WAS_CREATED) {
00912                 status = set_ea(conn, fsp, fname, ea_list);
00913                 if (!NT_STATUS_IS_OK(status)) {
00914                         close_file(fsp,ERROR_CLOSE);
00915                         return ERROR_NT(status);
00916                 }
00917         }
00918 
00919         /* Realloc the size of parameters and data we will return */
00920         *pparams = (char *)SMB_REALLOC(*pparams, 30);
00921         if(*pparams == NULL ) {
00922                 return ERROR_NT(NT_STATUS_NO_MEMORY);
00923         }
00924         params = *pparams;
00925 
00926         SSVAL(params,0,fsp->fnum);
00927         SSVAL(params,2,fattr);
00928         srv_put_dos_date2(params,4, mtime);
00929         SIVAL(params,8, (uint32)size);
00930         SSVAL(params,12,deny_mode);
00931         SSVAL(params,14,0); /* open_type - file or directory. */
00932         SSVAL(params,16,0); /* open_state - only valid for IPC device. */
00933 
00934         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
00935                 smb_action |= EXTENDED_OPLOCK_GRANTED;
00936         }
00937 
00938         SSVAL(params,18,smb_action);
00939 
00940         /*
00941          * WARNING - this may need to be changed if SMB_INO_T <> 4 bytes.
00942          */
00943         SIVAL(params,20,inode);
00944         SSVAL(params,24,0); /* Padding. */
00945         if (flags & 8) {
00946                 uint32 ea_size = estimate_ea_size(conn, fsp, fname);
00947                 SIVAL(params, 26, ea_size);
00948         } else {
00949                 SIVAL(params, 26, 0);
00950         }
00951 
00952         /* Send the required number of replies */
00953         send_trans2_replies(outbuf, bufsize, params, 30, *ppdata, 0, max_data_bytes);
00954 
00955         return -1;
00956 }
00957 
00958 /*********************************************************
00959  Routine to check if a given string matches exactly.
00960  as a special case a mask of "." does NOT match. That
00961  is required for correct wildcard semantics
00962  Case can be significant or not.
00963 **********************************************************/
00964 
00965 static BOOL exact_match(connection_struct *conn, char *str, char *mask)
00966 {
00967         if (mask[0] == '.' && mask[1] == 0)
00968                 return False;
00969         if (conn->case_sensitive)
00970                 return strcmp(str,mask)==0;
00971         if (StrCaseCmp(str,mask) != 0) {
00972                 return False;
00973         }
00974         if (dptr_has_wild(conn->dirptr)) {
00975                 return False;
00976         }
00977         return True;
00978 }
00979 
00980 /****************************************************************************
00981  Return the filetype for UNIX extensions.
00982 ****************************************************************************/
00983 
00984 static uint32 unix_filetype(mode_t mode)
00985 {
00986         if(S_ISREG(mode))
00987                 return UNIX_TYPE_FILE;
00988         else if(S_ISDIR(mode))
00989                 return UNIX_TYPE_DIR;
00990 #ifdef S_ISLNK
00991         else if(S_ISLNK(mode))
00992                 return UNIX_TYPE_SYMLINK;
00993 #endif
00994 #ifdef S_ISCHR
00995         else if(S_ISCHR(mode))
00996                 return UNIX_TYPE_CHARDEV;
00997 #endif
00998 #ifdef S_ISBLK
00999         else if(S_ISBLK(mode))
01000                 return UNIX_TYPE_BLKDEV;
01001 #endif
01002 #ifdef S_ISFIFO
01003         else if(S_ISFIFO(mode))
01004                 return UNIX_TYPE_FIFO;
01005 #endif
01006 #ifdef S_ISSOCK
01007         else if(S_ISSOCK(mode))
01008                 return UNIX_TYPE_SOCKET;
01009 #endif
01010 
01011         DEBUG(0,("unix_filetype: unknown filetype %u", (unsigned)mode));
01012         return UNIX_TYPE_UNKNOWN;
01013 }
01014 
01015 /****************************************************************************
01016  Map wire perms onto standard UNIX permissions. Obey share restrictions.
01017 ****************************************************************************/
01018 
01019 enum perm_type { PERM_NEW_FILE, PERM_NEW_DIR, PERM_EXISTING_FILE, PERM_EXISTING_DIR};
01020 
01021 static NTSTATUS unix_perms_from_wire( connection_struct *conn,
01022                                 SMB_STRUCT_STAT *psbuf,
01023                                 uint32 perms,
01024                                 enum perm_type ptype,
01025                                 mode_t *ret_perms)
01026 {
01027         mode_t ret = 0;
01028 
01029         if (perms == SMB_MODE_NO_CHANGE) {
01030                 if (!VALID_STAT(*psbuf)) {
01031                         return NT_STATUS_INVALID_PARAMETER;
01032                 } else {
01033                         *ret_perms = psbuf->st_mode;
01034                         return NT_STATUS_OK;
01035                 }
01036         }
01037 
01038         ret |= ((perms & UNIX_X_OTH ) ? S_IXOTH : 0);
01039         ret |= ((perms & UNIX_W_OTH ) ? S_IWOTH : 0);
01040         ret |= ((perms & UNIX_R_OTH ) ? S_IROTH : 0);
01041         ret |= ((perms & UNIX_X_GRP ) ? S_IXGRP : 0);
01042         ret |= ((perms & UNIX_W_GRP ) ? S_IWGRP : 0);
01043         ret |= ((perms & UNIX_R_GRP ) ? S_IRGRP : 0);
01044         ret |= ((perms & UNIX_X_USR ) ? S_IXUSR : 0);
01045         ret |= ((perms & UNIX_W_USR ) ? S_IWUSR : 0);
01046         ret |= ((perms & UNIX_R_USR ) ? S_IRUSR : 0);
01047 #ifdef S_ISVTX
01048         ret |= ((perms & UNIX_STICKY ) ? S_ISVTX : 0);
01049 #endif
01050 #ifdef S_ISGID
01051         ret |= ((perms & UNIX_SET_GID ) ? S_ISGID : 0);
01052 #endif
01053 #ifdef S_ISUID
01054         ret |= ((perms & UNIX_SET_UID ) ? S_ISUID : 0);
01055 #endif
01056 
01057         switch (ptype) {
01058         case PERM_NEW_FILE:
01059                 /* Apply mode mask */
01060                 ret &= lp_create_mask(SNUM(conn));
01061                 /* Add in force bits */
01062                 ret |= lp_force_create_mode(SNUM(conn));
01063                 break;
01064         case PERM_NEW_DIR:
01065                 ret &= lp_dir_mask(SNUM(conn));
01066                 /* Add in force bits */
01067                 ret |= lp_force_dir_mode(SNUM(conn));
01068                 break;
01069         case PERM_EXISTING_FILE:
01070                 /* Apply mode mask */
01071                 ret &= lp_security_mask(SNUM(conn));
01072                 /* Add in force bits */
01073                 ret |= lp_force_security_mode(SNUM(conn));
01074                 break;
01075         case PERM_EXISTING_DIR:
01076                 /* Apply mode mask */
01077                 ret &= lp_dir_security_mask(SNUM(conn));
01078                 /* Add in force bits */
01079                 ret |= lp_force_dir_security_mode(SNUM(conn));
01080                 break;
01081         }
01082 
01083         *ret_perms = ret;
01084         return NT_STATUS_OK;
01085 }
01086 
01087 /****************************************************************************
01088  Get a level dependent lanman2 dir entry.
01089 ****************************************************************************/
01090 
01091 static BOOL get_lanman2_dir_entry(connection_struct *conn,
01092                                   void *inbuf, char *outbuf,
01093                                  char *path_mask,uint32 dirtype,int info_level,
01094                                  int requires_resume_key,
01095                                  BOOL dont_descend,char **ppdata, 
01096                                  char *base_data, char *end_data, int space_remaining, 
01097                                  BOOL *out_of_space, BOOL *got_exact_match,
01098                                  int *last_entry_off, struct ea_list *name_list, TALLOC_CTX *ea_ctx)
01099 {
01100         const char *dname;
01101         BOOL found = False;
01102         SMB_STRUCT_STAT sbuf;
01103         pstring mask;
01104         pstring pathreal;
01105         pstring fname;
01106         char *p, *q, *pdata = *ppdata;
01107         uint32 reskey=0;
01108         long prev_dirpos=0;
01109         uint32 mode=0;
01110         SMB_OFF_T file_size = 0;
01111         SMB_BIG_UINT allocation_size = 0;
01112         uint32 len;
01113         struct timespec mdate_ts, adate_ts, create_date_ts;
01114         time_t mdate = (time_t)0, adate = (time_t)0, create_date = (time_t)0;
01115         char *nameptr;
01116         char *last_entry_ptr;
01117         BOOL was_8_3;
01118         uint32 nt_extmode; /* Used for NT connections instead of mode */
01119         BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
01120         BOOL check_mangled_names = lp_manglednames(conn->params);
01121 
01122         *fname = 0;
01123         *out_of_space = False;
01124         *got_exact_match = False;
01125 
01126         ZERO_STRUCT(mdate_ts);
01127         ZERO_STRUCT(adate_ts);
01128         ZERO_STRUCT(create_date_ts);
01129 
01130         if (!conn->dirptr)
01131                 return(False);
01132 
01133         p = strrchr_m(path_mask,'/');
01134         if(p != NULL) {
01135                 if(p[1] == '\0')
01136                         pstrcpy(mask,"*.*");
01137                 else
01138                         pstrcpy(mask, p+1);
01139         } else
01140                 pstrcpy(mask, path_mask);
01141 
01142 
01143         while (!found) {
01144                 BOOL got_match;
01145                 BOOL ms_dfs_link = False;
01146 
01147                 /* Needed if we run out of space */
01148                 long curr_dirpos = prev_dirpos = dptr_TellDir(conn->dirptr);
01149                 dname = dptr_ReadDirName(conn->dirptr,&curr_dirpos,&sbuf);
01150 
01151                 /*
01152                  * Due to bugs in NT client redirectors we are not using
01153                  * resume keys any more - set them to zero.
01154                  * Check out the related comments in findfirst/findnext.
01155                  * JRA.
01156                  */
01157 
01158                 reskey = 0;
01159 
01160                 DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %ld\n",
01161                         (long)conn->dirptr,curr_dirpos));
01162       
01163                 if (!dname) 
01164                         return(False);
01165 
01166                 pstrcpy(fname,dname);      
01167 
01168                 if(!(got_match = *got_exact_match = exact_match(conn, fname, mask)))
01169                         got_match = mask_match(fname, mask, conn->case_sensitive);
01170 
01171                 if(!got_match && check_mangled_names &&
01172                    !mangle_is_8_3(fname, False, conn->params)) {
01173 
01174                         /*
01175                          * It turns out that NT matches wildcards against
01176                          * both long *and* short names. This may explain some
01177                          * of the wildcard wierdness from old DOS clients
01178                          * that some people have been seeing.... JRA.
01179                          */
01180 
01181                         pstring newname;
01182                         pstrcpy( newname, fname);
01183                         mangle_map( newname, True, False, conn->params);
01184                         if(!(got_match = *got_exact_match = exact_match(conn, newname, mask)))
01185                                 got_match = mask_match(newname, mask, conn->case_sensitive);
01186                 }
01187 
01188                 if(got_match) {
01189                         BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
01190                         if (dont_descend && !isdots)
01191                                 continue;
01192           
01193                         pstrcpy(pathreal,conn->dirpath);
01194                         if(needslash)
01195                                 pstrcat(pathreal,"/");
01196                         pstrcat(pathreal,dname);
01197 
01198                         if (INFO_LEVEL_IS_UNIX(info_level)) {
01199                                 if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) {
01200                                         DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
01201                                                 pathreal,strerror(errno)));
01202                                         continue;
01203                                 }
01204                         } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
01205                                 pstring link_target;
01206 
01207                                 /* Needed to show the msdfs symlinks as 
01208                                  * directories */
01209 
01210                                 if(lp_host_msdfs() && 
01211                                    lp_msdfs_root(SNUM(conn)) &&
01212                                    ((ms_dfs_link = is_msdfs_link(conn, pathreal, link_target, &sbuf)) == True)) {
01213                                         DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s "
01214                                                 "as a directory\n",
01215                                                 pathreal));
01216                                         sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
01217 
01218                                 } else {
01219 
01220                                         DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
01221                                                 pathreal,strerror(errno)));
01222                                         continue;
01223                                 }
01224                         }
01225 
01226                         if (ms_dfs_link) {
01227                                 mode = dos_mode_msdfs(conn,pathreal,&sbuf);
01228                         } else {
01229                                 mode = dos_mode(conn,pathreal,&sbuf);
01230                         }
01231 
01232                         if (!dir_check_ftype(conn,mode,dirtype)) {
01233                                 DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
01234                                 continue;
01235                         }
01236 
01237                         if (!(mode & aDIR))
01238                                 file_size = get_file_size(sbuf);
01239                         allocation_size = get_allocation_size(conn,NULL,&sbuf);
01240 
01241                         mdate_ts = get_mtimespec(&sbuf);
01242                         adate_ts = get_atimespec(&sbuf);
01243                         create_date_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
01244 
01245                         if (lp_dos_filetime_resolution(SNUM(conn))) {
01246                                 dos_filetime_timespec(&create_date_ts);
01247                                 dos_filetime_timespec(&mdate_ts);
01248                                 dos_filetime_timespec(&adate_ts);
01249                         }
01250 
01251                         create_date = convert_timespec_to_time_t(create_date_ts);
01252                         mdate = convert_timespec_to_time_t(mdate_ts);
01253                         adate = convert_timespec_to_time_t(adate_ts);
01254                         
01255                         DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
01256           
01257                         found = True;
01258 
01259                         dptr_DirCacheAdd(conn->dirptr, dname, curr_dirpos);
01260                 }
01261         }
01262 
01263         mangle_map(fname,False,True,conn->params);
01264 
01265         p = pdata;
01266         last_entry_ptr = p;
01267 
01268         nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
01269 
01270         switch (info_level) {
01271                 case SMB_FIND_INFO_STANDARD:
01272                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_INFO_STANDARD\n"));
01273                         if(requires_resume_key) {
01274                                 SIVAL(p,0,reskey);
01275                                 p += 4;
01276                         }
01277                         srv_put_dos_date2(p,0,create_date);
01278                         srv_put_dos_date2(p,4,adate);
01279                         srv_put_dos_date2(p,8,mdate);
01280                         SIVAL(p,12,(uint32)file_size);
01281                         SIVAL(p,16,(uint32)allocation_size);
01282                         SSVAL(p,20,mode);
01283                         p += 23;
01284                         nameptr = p;
01285                         p += align_string(outbuf, p, 0);
01286                         len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE);
01287                         if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
01288                                 if (len > 2) {
01289                                         SCVAL(nameptr, -1, len - 2);
01290                                 } else {
01291                                         SCVAL(nameptr, -1, 0);
01292                                 }
01293                         } else {
01294                                 if (len > 1) {
01295                                         SCVAL(nameptr, -1, len - 1);
01296                                 } else {
01297                                         SCVAL(nameptr, -1, 0);
01298                                 }
01299                         }
01300                         p += len;
01301                         break;
01302 
01303                 case SMB_FIND_EA_SIZE:
01304                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_SIZE\n"));
01305                         if(requires_resume_key) {
01306                                 SIVAL(p,0,reskey);
01307                                 p += 4;
01308                         }
01309                         srv_put_dos_date2(p,0,create_date);
01310                         srv_put_dos_date2(p,4,adate);
01311                         srv_put_dos_date2(p,8,mdate);
01312                         SIVAL(p,12,(uint32)file_size);
01313                         SIVAL(p,16,(uint32)allocation_size);
01314                         SSVAL(p,20,mode);
01315                         {
01316                                 unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
01317                                 SIVAL(p,22,ea_size); /* Extended attributes */
01318                         }
01319                         p += 27;
01320                         nameptr = p - 1;
01321                         len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE | STR_NOALIGN);
01322                         if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
01323                                 if (len > 2) {
01324                                         len -= 2;
01325                                 } else {
01326                                         len = 0;
01327                                 }
01328                         } else {
01329                                 if (len > 1) {
01330                                         len -= 1;
01331                                 } else {
01332                                         len = 0;
01333                                 }
01334                         }
01335                         SCVAL(nameptr,0,len);
01336                         p += len;
01337                         SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
01338                         break;
01339 
01340                 case SMB_FIND_EA_LIST:
01341                 {
01342                         struct ea_list *file_list = NULL;
01343                         size_t ea_len = 0;
01344 
01345                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_EA_LIST\n"));
01346                         if (!name_list) {
01347                                 return False;
01348                         }
01349                         if(requires_resume_key) {
01350                                 SIVAL(p,0,reskey);
01351                                 p += 4;
01352                         }
01353                         srv_put_dos_date2(p,0,create_date);
01354                         srv_put_dos_date2(p,4,adate);
01355                         srv_put_dos_date2(p,8,mdate);
01356                         SIVAL(p,12,(uint32)file_size);
01357                         SIVAL(p,16,(uint32)allocation_size);
01358                         SSVAL(p,20,mode);
01359                         p += 22; /* p now points to the EA area. */
01360 
01361                         file_list = get_ea_list_from_file(ea_ctx, conn, NULL, pathreal, &ea_len);
01362                         name_list = ea_list_union(name_list, file_list, &ea_len);
01363 
01364                         /* We need to determine if this entry will fit in the space available. */
01365                         /* Max string size is 255 bytes. */
01366                         if (PTR_DIFF(p + 255 + ea_len,pdata) > space_remaining) {
01367                                 /* Move the dirptr back to prev_dirpos */
01368                                 dptr_SeekDir(conn->dirptr, prev_dirpos);
01369                                 *out_of_space = True;
01370                                 DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
01371                                 return False; /* Not finished - just out of space */
01372                         }
01373 
01374                         /* Push the ea_data followed by the name. */
01375                         p += fill_ea_buffer(ea_ctx, p, space_remaining - (p - pdata), conn, name_list);
01376                         nameptr = p;
01377                         len = srvstr_push(outbuf, p + 1, fname, PTR_DIFF(end_data, p+1), STR_TERMINATE | STR_NOALIGN);
01378                         if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
01379                                 if (len > 2) {
01380                                         len -= 2;
01381                                 } else {
01382                                         len = 0;
01383                                 }
01384                         } else {
01385                                 if (len > 1) {
01386                                         len -= 1;
01387                                 } else {
01388                                         len = 0;
01389                                 }
01390                         }
01391                         SCVAL(nameptr,0,len);
01392                         p += len + 1;
01393                         SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
01394                         break;
01395                 }
01396 
01397                 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
01398                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
01399                         was_8_3 = mangle_is_8_3(fname, True, conn->params);
01400                         p += 4;
01401                         SIVAL(p,0,reskey); p += 4;
01402                         put_long_date_timespec(p,create_date_ts); p += 8;
01403                         put_long_date_timespec(p,adate_ts); p += 8;
01404                         put_long_date_timespec(p,mdate_ts); p += 8;
01405                         put_long_date_timespec(p,mdate_ts); p += 8;
01406                         SOFF_T(p,0,file_size); p += 8;
01407                         SOFF_T(p,0,allocation_size); p += 8;
01408                         SIVAL(p,0,nt_extmode); p += 4;
01409                         q = p; p += 4; /* q is placeholder for name length. */
01410                         {
01411                                 unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
01412                                 SIVAL(p,0,ea_size); /* Extended attributes */
01413                                 p += 4;
01414                         }
01415                         /* Clear the short name buffer. This is
01416                          * IMPORTANT as not doing so will trigger
01417                          * a Win2k client bug. JRA.
01418                          */
01419                         if (!was_8_3 && check_mangled_names) {
01420                                 pstring mangled_name;
01421                                 pstrcpy(mangled_name, fname);
01422                                 mangle_map(mangled_name,True,True,
01423                                            conn->params);
01424                                 mangled_name[12] = 0;
01425                                 len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
01426                                 if (len < 24) {
01427                                         memset(p + 2 + len,'\0',24 - len);
01428                                 }
01429                                 SSVAL(p, 0, len);
01430                         } else {
01431                                 memset(p,'\0',26);
01432                         }
01433                         p += 2 + 24;
01434                         len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE_ASCII);
01435                         SIVAL(q,0,len);
01436                         p += len;
01437                         SIVAL(p,0,0); /* Ensure any padding is null. */
01438                         len = PTR_DIFF(p, pdata);
01439                         len = (len + 3) & ~3;
01440                         SIVAL(pdata,0,len);
01441                         p = pdata + len;
01442                         break;
01443 
01444                 case SMB_FIND_FILE_DIRECTORY_INFO:
01445                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
01446                         p += 4;
01447                         SIVAL(p,0,reskey); p += 4;
01448                         put_long_date_timespec(p,create_date_ts); p += 8;
01449                         put_long_date_timespec(p,adate_ts); p += 8;
01450                         put_long_date_timespec(p,mdate_ts); p += 8;
01451                         put_long_date_timespec(p,mdate_ts); p += 8;
01452                         SOFF_T(p,0,file_size); p += 8;
01453                         SOFF_T(p,0,allocation_size); p += 8;
01454                         SIVAL(p,0,nt_extmode); p += 4;
01455                         len = srvstr_push(outbuf, p + 4, fname, PTR_DIFF(end_data, p+4), STR_TERMINATE_ASCII);
01456                         SIVAL(p,0,len);
01457                         p += 4 + len;
01458                         SIVAL(p,0,0); /* Ensure any padding is null. */
01459                         len = PTR_DIFF(p, pdata);
01460                         len = (len + 3) & ~3;
01461                         SIVAL(pdata,0,len);
01462                         p = pdata + len;
01463                         break;
01464       
01465                 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
01466                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
01467                         p += 4;
01468                         SIVAL(p,0,reskey); p += 4;
01469                         put_long_date_timespec(p,create_date_ts); p += 8;
01470                         put_long_date_timespec(p,adate_ts); p += 8;
01471                         put_long_date_timespec(p,mdate_ts); p += 8;
01472                         put_long_date_timespec(p,mdate_ts); p += 8;
01473                         SOFF_T(p,0,file_size); p += 8;
01474                         SOFF_T(p,0,allocation_size); p += 8;
01475                         SIVAL(p,0,nt_extmode); p += 4;
01476                         q = p; p += 4; /* q is placeholder for name length. */
01477                         {
01478                                 unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
01479                                 SIVAL(p,0,ea_size); /* Extended attributes */
01480                                 p +=4;
01481                         }
01482                         len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE_ASCII);
01483                         SIVAL(q, 0, len);
01484                         p += len;
01485 
01486                         SIVAL(p,0,0); /* Ensure any padding is null. */
01487                         len = PTR_DIFF(p, pdata);
01488                         len = (len + 3) & ~3;
01489                         SIVAL(pdata,0,len);
01490                         p = pdata + len;
01491                         break;
01492 
01493                 case SMB_FIND_FILE_NAMES_INFO:
01494                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
01495                         p += 4;
01496                         SIVAL(p,0,reskey); p += 4;
01497                         p += 4;
01498                         /* this must *not* be null terminated or w2k gets in a loop trying to set an
01499                            acl on a dir (tridge) */
01500                         len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE_ASCII);
01501                         SIVAL(p, -4, len);
01502                         p += len;
01503                         SIVAL(p,0,0); /* Ensure any padding is null. */
01504                         len = PTR_DIFF(p, pdata);
01505                         len = (len + 3) & ~3;
01506                         SIVAL(pdata,0,len);
01507                         p = pdata + len;
01508                         break;
01509 
01510                 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
01511                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
01512                         p += 4;
01513                         SIVAL(p,0,reskey); p += 4;
01514                         put_long_date_timespec(p,create_date_ts); p += 8;
01515                         put_long_date_timespec(p,adate_ts); p += 8;
01516                         put_long_date_timespec(p,mdate_ts); p += 8;
01517                         put_long_date_timespec(p,mdate_ts); p += 8;
01518                         SOFF_T(p,0,file_size); p += 8;
01519                         SOFF_T(p,0,allocation_size); p += 8;
01520                         SIVAL(p,0,nt_extmode); p += 4;
01521                         q = p; p += 4; /* q is placeholder for name length. */
01522                         {
01523                                 unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
01524                                 SIVAL(p,0,ea_size); /* Extended attributes */
01525                                 p +=4;
01526                         }
01527                         SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
01528                         SIVAL(p,0,sbuf.st_ino); p += 4; /* FileIndexLow */
01529                         SIVAL(p,0,sbuf.st_dev); p += 4; /* FileIndexHigh */
01530                         len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE_ASCII);
01531                         SIVAL(q, 0, len);
01532                         p += len; 
01533                         SIVAL(p,0,0); /* Ensure any padding is null. */
01534                         len = PTR_DIFF(p, pdata);
01535                         len = (len + 3) & ~3;
01536                         SIVAL(pdata,0,len);
01537                         p = pdata + len;
01538                         break;
01539 
01540                 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
01541                         DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
01542                         was_8_3 = mangle_is_8_3(fname, True, conn->params);
01543                         p += 4;
01544                         SIVAL(p,0,reskey); p += 4;
01545                         put_long_date_timespec(p,create_date_ts); p += 8;
01546                         put_long_date_timespec(p,adate_ts); p += 8;
01547                         put_long_date_timespec(p,mdate_ts); p += 8;
01548                         put_long_date_timespec(p,mdate_ts); p += 8;
01549                         SOFF_T(p,0,file_size); p += 8;
01550                         SOFF_T(p,0,allocation_size); p += 8;
01551                         SIVAL(p,0,nt_extmode); p += 4;
01552                         q = p; p += 4; /* q is placeholder for name length */
01553                         {
01554                                 unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
01555                                 SIVAL(p,0,ea_size); /* Extended attributes */
01556                                 p +=4;
01557                         }
01558                         /* Clear the short name buffer. This is
01559                          * IMPORTANT as not doing so will trigger
01560                          * a Win2k client bug. JRA.
01561                          */
01562                         if (!was_8_3 && check_mangled_names) {
01563                                 pstring mangled_name;
01564                                 pstrcpy(mangled_name, fname);
01565                                 mangle_map(mangled_name,True,True,
01566                                            conn->params);
01567                                 mangled_name[12] = 0;
01568                                 len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
01569                                 SSVAL(p, 0, len);
01570                                 if (len < 24) {
01571                                         memset(p + 2 + len,'\0',24 - len);
01572                                 }
01573                                 SSVAL(p, 0, len);
01574                         } else {
01575                                 memset(p,'\0',26);
01576                         }
01577                         p += 26;
01578                         SSVAL(p,0,0); p += 2; /* Reserved ? */
01579                         SIVAL(p,0,sbuf.st_ino); p += 4; /* FileIndexLow */
01580                         SIVAL(p,0,sbuf.st_dev); p += 4; /* FileIndexHigh */
01581                         len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE_ASCII);
01582                         SIVAL(q,0,len);
01583                         p += len;
01584                         SIVAL(p,0,0); /* Ensure any padding is null. */
01585                         len = PTR_DIFF(p, pdata);
01586                         len = (len + 3) & ~3;
01587                         SIVAL(pdata,0,len);
01588                         p = pdata + len;
01589                         break;
01590 
01591                 /* CIFS UNIX Extension. */
01592 
01593                 case SMB_FIND_FILE_UNIX:
01594                 case SMB_FIND_FILE_UNIX_INFO2:
01595                         p+= 4;
01596                         SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */
01597 
01598                         /* Begin of SMB_QUERY_FILE_UNIX_BASIC */
01599 
01600                         if (info_level == SMB_FIND_FILE_UNIX) {
01601                                 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
01602                                 p = store_file_unix_basic(conn, p,
01603                                                         NULL, &sbuf);
01604                                 len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), STR_TERMINATE);
01605                         } else {
01606                                 DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX_INFO2\n"));
01607                                 p = store_file_unix_basic_info2(conn, p,
01608                                                         NULL, &sbuf);
01609                                 nameptr = p;
01610                                 p += 4;
01611                                 len = srvstr_push(outbuf, p, fname, PTR_DIFF(end_data, p), 0);
01612                                 SIVAL(nameptr, 0, len);
01613                         }
01614 
01615                         p += len;
01616                         SIVAL(p,0,0); /* Ensure any padding is null. */
01617 
01618                         len = PTR_DIFF(p, pdata);
01619                         len = (len + 3) & ~3;
01620                         SIVAL(pdata,0,len);     /* Offset from this structure to the beginning of the next one */
01621                         p = pdata + len;
01622                         /* End of SMB_QUERY_FILE_UNIX_BASIC */
01623 
01624                         break;
01625 
01626                 default:      
01627                         return(False);
01628         }
01629 
01630 
01631         if (PTR_DIFF(p,pdata) > space_remaining) {
01632                 /* Move the dirptr back to prev_dirpos */
01633                 dptr_SeekDir(conn->dirptr, prev_dirpos);
01634                 *out_of_space = True;
01635                 DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
01636                 return False; /* Not finished - just out of space */
01637         }
01638 
01639         /* Setup the last entry pointer, as an offset from base_data */
01640         *last_entry_off = PTR_DIFF(last_entry_ptr,base_data);
01641         /* Advance the data pointer to the next slot */
01642         *ppdata = p;
01643 
01644         return(found);
01645 }
01646 
01647 /****************************************************************************
01648  Reply to a TRANS2_FINDFIRST.
01649 ****************************************************************************/
01650 
01651 static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
01652                                 char **pparams, int total_params, char **ppdata, int total_data,
01653                                 unsigned int max_data_bytes)
01654 {
01655         /* We must be careful here that we don't return more than the
01656                 allowed number of data bytes. If this means returning fewer than
01657                 maxentries then so be it. We assume that the redirector has
01658                 enough room for the fixed number of parameter bytes it has
01659                 requested. */
01660         char *params = *pparams;
01661         char *pdata = *ppdata;
01662         char *data_end;
01663         uint32 dirtype;
01664         int maxentries;
01665         uint16 findfirst_flags;
01666         BOOL close_after_first;
01667         BOOL close_if_end;
01668         BOOL requires_resume_key;
01669         int info_level;
01670         pstring directory;
01671         pstring mask;
01672         char *p;
01673         int last_entry_off=0;
01674         int dptr_num = -1;
01675         int numentries = 0;
01676         int i;
01677         BOOL finished = False;
01678         BOOL dont_descend = False;
01679         BOOL out_of_space = False;
01680         int space_remaining;
01681         BOOL mask_contains_wcard = False;
01682         SMB_STRUCT_STAT sbuf;
01683         TALLOC_CTX *ea_ctx = NULL;
01684         struct ea_list *ea_list = NULL;
01685         NTSTATUS ntstatus = NT_STATUS_OK;
01686 
01687         if (total_params < 13) {
01688                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
01689         }
01690 
01691         dirtype = SVAL(params,0);
01692         maxentries = SVAL(params,2);
01693         findfirst_flags = SVAL(params,4);
01694         close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
01695         close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
01696         requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
01697         info_level = SVAL(params,6);
01698 
01699         *directory = *mask = 0;
01700 
01701         DEBUG(3,("call_trans2findfirst: dirtype = %x, maxentries = %d, close_after_first=%d, \
01702 close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
01703                 (unsigned int)dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
01704                 info_level, max_data_bytes));
01705 
01706         if (!maxentries) {
01707                 /* W2K3 seems to treat zero as 1. */
01708                 maxentries = 1;
01709         }
01710  
01711         switch (info_level) {
01712                 case SMB_FIND_INFO_STANDARD:
01713                 case SMB_FIND_EA_SIZE:
01714                 case SMB_FIND_EA_LIST:
01715                 case SMB_FIND_FILE_DIRECTORY_INFO:
01716                 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
01717                 case SMB_FIND_FILE_NAMES_INFO:
01718                 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
01719                 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
01720                 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
01721                         break;
01722                 case SMB_FIND_FILE_UNIX:
01723                 case SMB_FIND_FILE_UNIX_INFO2:
01724                         if (!lp_unix_extensions()) {
01725                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
01726                         }
01727                         break;
01728                 default:
01729                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
01730         }
01731 
01732         srvstr_get_path_wcard(inbuf, directory, params+12, sizeof(directory), total_params - 12, STR_TERMINATE, &ntstatus, &mask_contains_wcard);
01733         if (!NT_STATUS_IS_OK(ntstatus)) {
01734                 return ERROR_NT(ntstatus);
01735         }
01736 
01737         ntstatus = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory, &mask_contains_wcard);
01738         if (!NT_STATUS_IS_OK(ntstatus)) {
01739                 if (NT_STATUS_EQUAL(ntstatus,NT_STATUS_PATH_NOT_COVERED)) {
01740                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
01741                 }
01742                 return ERROR_NT(ntstatus);
01743         }
01744 
01745         ntstatus = unix_convert(conn, directory, True, NULL, &sbuf);
01746         if (!NT_STATUS_IS_OK(ntstatus)) {
01747                 return ERROR_NT(ntstatus);
01748         }
01749         ntstatus = check_name(conn, directory);
01750         if (!NT_STATUS_IS_OK(ntstatus)) {
01751                 return ERROR_NT(ntstatus);
01752         }
01753 
01754         p = strrchr_m(directory,'/');
01755         if(p == NULL) {
01756                 /* Windows and OS/2 systems treat search on the root '\' as if it were '\*' */
01757                 if((directory[0] == '.') && (directory[1] == '\0')) {
01758                         pstrcpy(mask,"*");
01759                         mask_contains_wcard = True;
01760                 } else {
01761                         pstrcpy(mask,directory);
01762                 }
01763                 pstrcpy(directory,"./");
01764         } else {
01765                 pstrcpy(mask,p+1);
01766                 *p = 0;
01767         }
01768 
01769         DEBUG(5,("dir=%s, mask = %s\n",directory, mask));
01770 
01771         if (info_level == SMB_FIND_EA_LIST) {
01772                 uint32 ea_size;
01773 
01774                 if (total_data < 4) {
01775                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
01776                 }
01777 
01778                 ea_size = IVAL(pdata,0);
01779                 if (ea_size != total_data) {
01780                         DEBUG(4,("call_trans2findfirst: Rejecting EA request with incorrect \
01781 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
01782                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
01783                 }
01784 
01785                 if (!lp_ea_support(SNUM(conn))) {
01786                         return ERROR_DOS(ERRDOS,ERReasnotsupported);
01787                 }
01788                                                                                                                                                         
01789                 if ((ea_ctx = talloc_init("findnext_ea_list")) == NULL) {
01790                         return ERROR_NT(NT_STATUS_NO_MEMORY);
01791                 }
01792 
01793                 /* Pull out the list of names. */
01794                 ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
01795                 if (!ea_list) {
01796                         talloc_destroy(ea_ctx);
01797                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
01798                 }
01799         }
01800 
01801         *ppdata = (char *)SMB_REALLOC(
01802                 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
01803         if(*ppdata == NULL ) {
01804                 talloc_destroy(ea_ctx);
01805                 return ERROR_NT(NT_STATUS_NO_MEMORY);
01806         }
01807         pdata = *ppdata;
01808         data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
01809 
01810         /* Realloc the params space */
01811         *pparams = (char *)SMB_REALLOC(*pparams, 10);
01812         if (*pparams == NULL) {
01813                 talloc_destroy(ea_ctx);
01814                 return ERROR_NT(NT_STATUS_NO_MEMORY);
01815         }
01816         params = *pparams;
01817 
01818         /* Save the wildcard match and attribs we are using on this directory - 
01819                 needed as lanman2 assumes these are being saved between calls */
01820 
01821         ntstatus = dptr_create(conn,
01822                                 directory,
01823                                 False,
01824                                 True,
01825                                 SVAL(inbuf,smb_pid),
01826                                 mask,
01827                                 mask_contains_wcard,
01828                                 dirtype,
01829                                 &conn->dirptr);
01830 
01831         if (!NT_STATUS_IS_OK(ntstatus)) {
01832                 talloc_destroy(ea_ctx);
01833                 return ERROR_NT(ntstatus);
01834         }
01835 
01836         dptr_num = dptr_dnum(conn->dirptr);
01837         DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
01838 
01839         /* We don't need to check for VOL here as this is returned by 
01840                 a different TRANS2 call. */
01841   
01842         DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn))));
01843         if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
01844                 dont_descend = True;
01845     
01846         p = pdata;
01847         space_remaining = max_data_bytes;
01848         out_of_space = False;
01849 
01850         for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
01851                 BOOL got_exact_match = False;
01852 
01853                 /* this is a heuristic to avoid seeking the dirptr except when 
01854                         absolutely necessary. It allows for a filename of about 40 chars */
01855                 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
01856                         out_of_space = True;
01857                         finished = False;
01858                 } else {
01859                         finished = !get_lanman2_dir_entry(conn,
01860                                         inbuf, outbuf,
01861                                         mask,dirtype,info_level,
01862                                         requires_resume_key,dont_descend,
01863                                         &p,pdata,data_end,space_remaining, &out_of_space, &got_exact_match,
01864                                         &last_entry_off, ea_list, ea_ctx);
01865                 }
01866 
01867                 if (finished && out_of_space)
01868                         finished = False;
01869 
01870                 if (!finished && !out_of_space)
01871                         numentries++;
01872 
01873                 /*
01874                  * As an optimisation if we know we aren't looking
01875                  * for a wildcard name (ie. the name matches the wildcard exactly)
01876                  * then we can finish on any (first) match.
01877                  * This speeds up large directory searches. JRA.
01878                  */
01879 
01880                 if(got_exact_match)
01881                         finished = True;
01882 
01883                 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
01884         }
01885   
01886         talloc_destroy(ea_ctx);
01887 
01888         /* Check if we can close the dirptr */
01889         if(close_after_first || (finished && close_if_end)) {
01890                 DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
01891                 dptr_close(&dptr_num);
01892         }
01893 
01894         /* 
01895          * If there are no matching entries we must return ERRDOS/ERRbadfile - 
01896          * from observation of NT. NB. This changes to ERRDOS,ERRnofiles if
01897          * the protocol level is less than NT1. Tested with smbclient. JRA.
01898          * This should fix the OS/2 client bug #2335.
01899          */
01900 
01901         if(numentries == 0) {
01902                 dptr_close(&dptr_num);
01903                 if (Protocol < PROTOCOL_NT1) {
01904                         return ERROR_DOS(ERRDOS,ERRnofiles);
01905                 } else {
01906                         return ERROR_BOTH(NT_STATUS_NO_SUCH_FILE,ERRDOS,ERRbadfile);
01907                 }
01908         }
01909 
01910         /* At this point pdata points to numentries directory entries. */
01911 
01912         /* Set up the return parameter block */
01913         SSVAL(params,0,dptr_num);
01914         SSVAL(params,2,numentries);
01915         SSVAL(params,4,finished);
01916         SSVAL(params,6,0); /* Never an EA error */
01917         SSVAL(params,8,last_entry_off);
01918 
01919         send_trans2_replies( outbuf, bufsize, params, 10, pdata, PTR_DIFF(p,pdata), max_data_bytes);
01920 
01921         if ((! *directory) && dptr_path(dptr_num))
01922                 slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
01923 
01924         DEBUG( 4, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
01925                 smb_fn_name(CVAL(inbuf,smb_com)), 
01926                 mask, directory, dirtype, numentries ) );
01927 
01928         /* 
01929          * Force a name mangle here to ensure that the
01930          * mask as an 8.3 name is top of the mangled cache.
01931          * The reasons for this are subtle. Don't remove
01932          * this code unless you know what you are doing
01933          * (see PR#13758). JRA.
01934          */
01935 
01936         if(!mangle_is_8_3_wildcards( mask, False, conn->params))
01937                 mangle_map(mask, True, True, conn->params);
01938 
01939         return(-1);
01940 }
01941 
01942 /****************************************************************************
01943  Reply to a TRANS2_FINDNEXT.
01944 ****************************************************************************/
01945 
01946 static int call_trans2findnext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
01947                                         char **pparams, int total_params, char **ppdata, int total_data,
01948                                         unsigned int max_data_bytes)
01949 {
01950         /* We must be careful here that we don't return more than the
01951                 allowed number of data bytes. If this means returning fewer than
01952                 maxentries then so be it. We assume that the redirector has
01953                 enough room for the fixed number of parameter bytes it has
01954                 requested. */
01955         char *params = *pparams;
01956         char *pdata = *ppdata;
01957         char *data_end;
01958         int dptr_num;
01959         int maxentries;
01960         uint16 info_level;
01961         uint32 resume_key;
01962         uint16 findnext_flags;
01963         BOOL close_after_request;
01964         BOOL close_if_end;
01965         BOOL requires_resume_key;
01966         BOOL continue_bit;
01967         BOOL mask_contains_wcard = False;
01968         pstring resume_name;
01969         pstring mask;
01970         pstring directory;
01971         char *p;
01972         uint16 dirtype;
01973         int numentries = 0;
01974         int i, last_entry_off=0;
01975         BOOL finished = False;
01976         BOOL dont_descend = False;
01977         BOOL out_of_space = False;
01978         int space_remaining;
01979         TALLOC_CTX *ea_ctx = NULL;
01980         struct ea_list *ea_list = NULL;
01981         NTSTATUS ntstatus = NT_STATUS_OK;
01982 
01983         if (total_params < 13) {
01984                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
01985         }
01986 
01987         dptr_num = SVAL(params,0);
01988         maxentries = SVAL(params,2);
01989         info_level = SVAL(params,4);
01990         resume_key = IVAL(params,6);
01991         findnext_flags = SVAL(params,10);
01992         close_after_request = (findnext_flags & FLAG_TRANS2_FIND_CLOSE);
01993         close_if_end = (findnext_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
01994         requires_resume_key = (findnext_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
01995         continue_bit = (findnext_flags & FLAG_TRANS2_FIND_CONTINUE);
01996 
01997         *mask = *directory = *resume_name = 0;
01998 
01999         srvstr_get_path_wcard(inbuf, resume_name, params+12, sizeof(resume_name), total_params - 12, STR_TERMINATE, &ntstatus, &mask_contains_wcard);
02000         if (!NT_STATUS_IS_OK(ntstatus)) {
02001                 /* Win9x or OS/2 can send a resume name of ".." or ".". This will cause the parser to
02002                    complain (it thinks we're asking for the directory above the shared
02003                    path or an invalid name). Catch this as the resume name is only compared, never used in
02004                    a file access. JRA. */
02005                 srvstr_pull(inbuf, resume_name, params+12,
02006                                         sizeof(resume_name), total_params - 12,
02007                                         STR_TERMINATE);
02008 
02009                 if (!(ISDOT(resume_name) || ISDOTDOT(resume_name))) {
02010                         return ERROR_NT(ntstatus);
02011                 }
02012         }
02013 
02014         DEBUG(3,("call_trans2findnext: dirhandle = %d, max_data_bytes = %d, maxentries = %d, \
02015 close_after_request=%d, close_if_end = %d requires_resume_key = %d \
02016 resume_key = %d resume name = %s continue=%d level = %d\n",
02017                 dptr_num, max_data_bytes, maxentries, close_after_request, close_if_end, 
02018                 requires_resume_key, resume_key, resume_name, continue_bit, info_level));
02019 
02020         if (!maxentries) {
02021                 /* W2K3 seems to treat zero as 1. */
02022                 maxentries = 1;
02023         }
02024 
02025         switch (info_level) {
02026                 case SMB_FIND_INFO_STANDARD:
02027                 case SMB_FIND_EA_SIZE:
02028                 case SMB_FIND_EA_LIST:
02029                 case SMB_FIND_FILE_DIRECTORY_INFO:
02030                 case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
02031                 case SMB_FIND_FILE_NAMES_INFO:
02032                 case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
02033                 case SMB_FIND_ID_FULL_DIRECTORY_INFO:
02034                 case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
02035                         break;
02036                 case SMB_FIND_FILE_UNIX:
02037                 case SMB_FIND_FILE_UNIX_INFO2:
02038                         if (!lp_unix_extensions()) {
02039                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02040                         }
02041                         break;
02042                 default:
02043                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02044         }
02045 
02046         if (info_level == SMB_FIND_EA_LIST) {
02047                 uint32 ea_size;
02048 
02049                 if (total_data < 4) {
02050                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02051                 }
02052 
02053                 ea_size = IVAL(pdata,0);
02054                 if (ea_size != total_data) {
02055                         DEBUG(4,("call_trans2findnext: Rejecting EA request with incorrect \
02056 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
02057                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02058                 }
02059                                                                                                                                                      
02060                 if (!lp_ea_support(SNUM(conn))) {
02061                         return ERROR_DOS(ERRDOS,ERReasnotsupported);
02062                 }
02063                                                                                                                                                      
02064                 if ((ea_ctx = talloc_init("findnext_ea_list")) == NULL) {
02065                         return ERROR_NT(NT_STATUS_NO_MEMORY);
02066                 }
02067 
02068                 /* Pull out the list of names. */
02069                 ea_list = read_ea_name_list(ea_ctx, pdata + 4, ea_size - 4);
02070                 if (!ea_list) {
02071                         talloc_destroy(ea_ctx);
02072                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02073                 }
02074         }
02075 
02076         *ppdata = (char *)SMB_REALLOC(
02077                 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
02078         if(*ppdata == NULL) {
02079                 talloc_destroy(ea_ctx);
02080                 return ERROR_NT(NT_STATUS_NO_MEMORY);
02081         }
02082 
02083         pdata = *ppdata;
02084         data_end = pdata + max_data_bytes + DIR_ENTRY_SAFETY_MARGIN - 1;
02085 
02086         /* Realloc the params space */
02087         *pparams = (char *)SMB_REALLOC(*pparams, 6*SIZEOFWORD);
02088         if(*pparams == NULL ) {
02089                 talloc_destroy(ea_ctx);
02090                 return ERROR_NT(NT_STATUS_NO_MEMORY);
02091         }
02092 
02093         params = *pparams;
02094 
02095         /* Check that the dptr is valid */
02096         if(!(conn->dirptr = dptr_fetch_lanman2(dptr_num))) {
02097                 talloc_destroy(ea_ctx);
02098                 return ERROR_DOS(ERRDOS,ERRnofiles);
02099         }
02100 
02101         string_set(&conn->dirpath,dptr_path(dptr_num));
02102 
02103         /* Get the wildcard mask from the dptr */
02104         if((p = dptr_wcard(dptr_num))== NULL) {
02105                 DEBUG(2,("dptr_num %d has no wildcard\n", dptr_num));
02106                 talloc_destroy(ea_ctx);
02107                 return ERROR_DOS(ERRDOS,ERRnofiles);
02108         }
02109 
02110         pstrcpy(mask, p);
02111         pstrcpy(directory,conn->dirpath);
02112 
02113         /* Get the attr mask from the dptr */
02114         dirtype = dptr_attr(dptr_num);
02115 
02116         DEBUG(3,("dptr_num is %d, mask = %s, attr = %x, dirptr=(0x%lX,%ld)\n",
02117                 dptr_num, mask, dirtype, 
02118                 (long)conn->dirptr,
02119                 dptr_TellDir(conn->dirptr)));
02120 
02121         /* We don't need to check for VOL here as this is returned by 
02122                 a different TRANS2 call. */
02123 
02124         DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",conn->dirpath,lp_dontdescend(SNUM(conn))));
02125         if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
02126                 dont_descend = True;
02127     
02128         p = pdata;
02129         space_remaining = max_data_bytes;
02130         out_of_space = False;
02131 
02132         /* 
02133          * Seek to the correct position. We no longer use the resume key but
02134          * depend on the last file name instead.
02135          */
02136 
02137         if(*resume_name && !continue_bit) {
02138                 SMB_STRUCT_STAT st;
02139 
02140                 long current_pos = 0;
02141                 /*
02142                  * Remember, mangle_map is called by
02143                  * get_lanman2_dir_entry(), so the resume name
02144                  * could be mangled. Ensure we check the unmangled name.
02145                  */
02146 
02147                 if (mangle_is_mangled(resume_name, conn->params)) {
02148                         mangle_check_cache(resume_name, sizeof(resume_name)-1,
02149                                            conn->params);
02150                 }
02151 
02152                 /*
02153                  * Fix for NT redirector problem triggered by resume key indexes
02154                  * changing between directory scans. We now return a resume key of 0
02155                  * and instead look for the filename to continue from (also given
02156                  * to us by NT/95/smbfs/smbclient). If no other scans have been done between the
02157                  * findfirst/findnext (as is usual) then the directory pointer
02158                  * should already be at the correct place.
02159                  */
02160 
02161                 finished = !dptr_SearchDir(conn->dirptr, resume_name, &current_pos, &st);
02162         } /* end if resume_name && !continue_bit */
02163 
02164         for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
02165                 BOOL got_exact_match = False;
02166 
02167                 /* this is a heuristic to avoid seeking the dirptr except when 
02168                         absolutely necessary. It allows for a filename of about 40 chars */
02169                 if (space_remaining < DIRLEN_GUESS && numentries > 0) {
02170                         out_of_space = True;
02171                         finished = False;
02172                 } else {
02173                         finished = !get_lanman2_dir_entry(conn,
02174                                                 inbuf, outbuf,
02175                                                 mask,dirtype,info_level,
02176                                                 requires_resume_key,dont_descend,
02177                                                 &p,pdata,data_end,space_remaining, &out_of_space, &got_exact_match,
02178                                                 &last_entry_off, ea_list, ea_ctx);
02179                 }
02180 
02181                 if (finished && out_of_space)
02182                         finished = False;
02183 
02184                 if (!finished && !out_of_space)
02185                         numentries++;
02186 
02187                 /*
02188                  * As an optimisation if we know we aren't looking
02189                  * for a wildcard name (ie. the name matches the wildcard exactly)
02190                  * then we can finish on any (first) match.
02191                  * This speeds up large directory searches. JRA.
02192                  */
02193 
02194                 if(got_exact_match)
02195                         finished = True;
02196 
02197                 space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
02198         }
02199   
02200         talloc_destroy(ea_ctx);
02201 
02202         /* Check if we can close the dirptr */
02203         if(close_after_request || (finished && close_if_end)) {
02204                 DEBUG(5,("call_trans2findnext: closing dptr_num = %d\n", dptr_num));
02205                 dptr_close(&dptr_num); /* This frees up the saved mask */
02206         }
02207 
02208         /* Set up the return parameter block */
02209         SSVAL(params,0,numentries);
02210         SSVAL(params,2,finished);
02211         SSVAL(params,4,0); /* Never an EA error */
02212         SSVAL(params,6,last_entry_off);
02213 
02214         send_trans2_replies( outbuf, bufsize, params, 8, pdata, PTR_DIFF(p,pdata), max_data_bytes);
02215 
02216         if ((! *directory) && dptr_path(dptr_num))
02217                 slprintf(directory,sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
02218 
02219         DEBUG( 3, ( "%s mask=%s directory=%s dirtype=%d numentries=%d\n",
02220                 smb_fn_name(CVAL(inbuf,smb_com)), 
02221                 mask, directory, dirtype, numentries ) );
02222 
02223         return(-1);
02224 }
02225 
02226 static void samba_extended_info_version(struct smb_extended_info *extended_info)
02227 {
02228                                 SMB_ASSERT(extended_info != NULL);
02229 
02230                                 extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
02231                                 extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
02232                                                                                                                                                          | ((SAMBA_VERSION_MINOR & 0xff) << 16)
02233                                                                                                                                                          | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
02234 #ifdef SAMBA_VERSION_REVISION
02235                                 extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
02236 #endif
02237                                 extended_info->samba_subversion = 0;
02238 #ifdef SAMBA_VERSION_RC_RELEASE
02239                                 extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
02240 #else
02241 #ifdef SAMBA_VERSION_PRE_RELEASE
02242                                 extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
02243 #endif
02244 #endif
02245 #ifdef SAMBA_VERSION_VENDOR_PATCH
02246                                 extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
02247 #endif
02248                                 extended_info->samba_subversion = 0;
02249 #ifdef SAMBA_VERSION_GIT_COMMIT_TIME
02250                                 unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_GIT_COMMIT_TIME);
02251 #endif
02252 
02253                                 memset(extended_info->samba_version_string, 0,
02254                                                          sizeof(extended_info->samba_version_string));
02255 
02256                                 snprintf (extended_info->samba_version_string,
02257                                                                         sizeof(extended_info->samba_version_string),
02258                                                                         "%s", samba_version_string());
02259 }
02260 
02261 /****************************************************************************
02262  Reply to a TRANS2_QFSINFO (query filesystem info).
02263 ****************************************************************************/
02264 
02265 static int call_trans2qfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
02266                                         char **pparams, int total_params, char **ppdata, int total_data,
02267                                         unsigned int max_data_bytes)
02268 {
02269         char *pdata;
02270         char *params = *pparams;
02271         uint16 info_level;
02272         int data_len, len;
02273         SMB_STRUCT_STAT st;
02274         const char *vname = volume_label(SNUM(conn));
02275         int snum = SNUM(conn);
02276         char *fstype = lp_fstype(SNUM(conn));
02277         int quota_flag = 0;
02278 
02279         if (total_params < 2) {
02280                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02281         }
02282 
02283         info_level = SVAL(params,0);
02284 
02285         DEBUG(3,("call_trans2qfsinfo: level = %d\n", info_level));
02286 
02287         if(SMB_VFS_STAT(conn,".",&st)!=0) {
02288                 DEBUG(2,("call_trans2qfsinfo: stat of . failed (%s)\n", strerror(errno)));
02289                 return ERROR_DOS(ERRSRV,ERRinvdevice);
02290         }
02291 
02292         *ppdata = (char *)SMB_REALLOC(
02293                 *ppdata, max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
02294         if (*ppdata == NULL ) {
02295                 return ERROR_NT(NT_STATUS_NO_MEMORY);
02296         }
02297 
02298         pdata = *ppdata;
02299         memset((char *)pdata,'\0',max_data_bytes + DIR_ENTRY_SAFETY_MARGIN);
02300 
02301         switch (info_level) {
02302                 case SMB_INFO_ALLOCATION:
02303                 {
02304                         SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
02305                         data_len = 18;
02306                         if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
02307                                 return(UNIXERROR(ERRHRD,ERRgeneral));
02308                         }
02309 
02310                         block_size = lp_block_size(snum);
02311                         if (bsize < block_size) {
02312                                 SMB_BIG_UINT factor = block_size/bsize;
02313                                 bsize = block_size;
02314                                 dsize /= factor;
02315                                 dfree /= factor;
02316                         }
02317                         if (bsize > block_size) {
02318                                 SMB_BIG_UINT factor = bsize/block_size;
02319                                 bsize = block_size;
02320                                 dsize *= factor;
02321                                 dfree *= factor;
02322                         }
02323                         bytes_per_sector = 512;
02324                         sectors_per_unit = bsize/bytes_per_sector;
02325 
02326                         DEBUG(5,("call_trans2qfsinfo : SMB_INFO_ALLOCATION id=%x, bsize=%u, cSectorUnit=%u, \
02327 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)st.st_dev, (unsigned int)bsize, (unsigned int)sectors_per_unit,
02328                                 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
02329 
02330                         SIVAL(pdata,l1_idFileSystem,st.st_dev);
02331                         SIVAL(pdata,l1_cSectorUnit,sectors_per_unit);
02332                         SIVAL(pdata,l1_cUnit,dsize);
02333                         SIVAL(pdata,l1_cUnitAvail,dfree);
02334                         SSVAL(pdata,l1_cbSector,bytes_per_sector);
02335                         break;
02336                 }
02337 
02338                 case SMB_INFO_VOLUME:
02339                         /* Return volume name */
02340                         /* 
02341                          * Add volume serial number - hash of a combination of
02342                          * the called hostname and the service name.
02343                          */
02344                         SIVAL(pdata,0,str_checksum(lp_servicename(snum)) ^ (str_checksum(get_local_machine_name())<<16) );
02345                         /*
02346                          * Win2k3 and previous mess this up by sending a name length
02347                          * one byte short. I believe only older clients (OS/2 Win9x) use
02348                          * this call so try fixing this by adding a terminating null to
02349                          * the pushed string. The change here was adding the STR_TERMINATE. JRA.
02350                          */
02351                         len = srvstr_push(outbuf, pdata+l2_vol_szVolLabel, vname, max_data_bytes - l2_vol_szVolLabel, STR_NOALIGN|STR_TERMINATE);
02352                         SCVAL(pdata,l2_vol_cch,len);
02353                         data_len = l2_vol_szVolLabel + len;
02354                         DEBUG(5,("call_trans2qfsinfo : time = %x, namelen = %d, name = %s\n",
02355                                 (unsigned)st.st_ctime, len, vname));
02356                         break;
02357 
02358                 case SMB_QUERY_FS_ATTRIBUTE_INFO:
02359                 case SMB_FS_ATTRIBUTE_INFORMATION:
02360 
02361 
02362 #if defined(HAVE_SYS_QUOTAS)
02363                         quota_flag = FILE_VOLUME_QUOTAS;
02364 #endif
02365 
02366                         SIVAL(pdata,0,FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH|
02367                                 (lp_nt_acl_support(SNUM(conn)) ? FILE_PERSISTENT_ACLS : 0)|
02368                                 FILE_UNICODE_ON_DISK|
02369                                 quota_flag); /* FS ATTRIBUTES */
02370 
02371                         SIVAL(pdata,4,255); /* Max filename component length */
02372                         /* NOTE! the fstype must *not* be null terminated or win98 won't recognise it
02373                                 and will think we can't do long filenames */
02374                         len = srvstr_push(outbuf, pdata+12, fstype, max_data_bytes - 12, STR_UNICODE);
02375                         SIVAL(pdata,8,len);
02376                         data_len = 12 + len;
02377                         break;
02378 
02379                 case SMB_QUERY_FS_LABEL_INFO:
02380                 case SMB_FS_LABEL_INFORMATION:
02381                         len = srvstr_push(outbuf, pdata+4, vname, max_data_bytes - 4, 0);
02382                         data_len = 4 + len;
02383                         SIVAL(pdata,0,len);
02384                         break;
02385 
02386                 case SMB_QUERY_FS_VOLUME_INFO:      
02387                 case SMB_FS_VOLUME_INFORMATION:
02388 
02389                         /* 
02390                          * Add volume serial number - hash of a combination of
02391                          * the called hostname and the service name.
02392                          */
02393                         SIVAL(pdata,8,str_checksum(lp_servicename(snum)) ^ 
02394                                 (str_checksum(get_local_machine_name())<<16));
02395 
02396                         /* Max label len is 32 characters. */
02397                         len = srvstr_push(outbuf, pdata+18, vname, max_data_bytes - 18, STR_UNICODE);
02398                         SIVAL(pdata,12,len);
02399                         data_len = 18+len;
02400 
02401                         DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_VOLUME_INFO namelen = %d, vol=%s serv=%s\n", 
02402                                 (int)strlen(vname),vname, lp_servicename(snum)));
02403                         break;
02404 
02405                 case SMB_QUERY_FS_SIZE_INFO:
02406                 case SMB_FS_SIZE_INFORMATION:
02407                 {
02408                         SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
02409                         data_len = 24;
02410                         if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
02411                                 return(UNIXERROR(ERRHRD,ERRgeneral));
02412                         }
02413                         block_size = lp_block_size(snum);
02414                         if (bsize < block_size) {
02415                                 SMB_BIG_UINT factor = block_size/bsize;
02416                                 bsize = block_size;
02417                                 dsize /= factor;
02418                                 dfree /= factor;
02419                         }
02420                         if (bsize > block_size) {
02421                                 SMB_BIG_UINT factor = bsize/block_size;
02422                                 bsize = block_size;
02423                                 dsize *= factor;
02424                                 dfree *= factor;
02425                         }
02426                         bytes_per_sector = 512;
02427                         sectors_per_unit = bsize/bytes_per_sector;
02428                         DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_SIZE_INFO bsize=%u, cSectorUnit=%u, \
02429 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
02430                                 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
02431                         SBIG_UINT(pdata,0,dsize);
02432                         SBIG_UINT(pdata,8,dfree);
02433                         SIVAL(pdata,16,sectors_per_unit);
02434                         SIVAL(pdata,20,bytes_per_sector);
02435                         break;
02436                 }
02437 
02438                 case SMB_FS_FULL_SIZE_INFORMATION:
02439                 {
02440                         SMB_BIG_UINT dfree,dsize,bsize,block_size,sectors_per_unit,bytes_per_sector;
02441                         data_len = 32;
02442                         if (get_dfree_info(conn,".",False,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
02443                                 return(UNIXERROR(ERRHRD,ERRgeneral));
02444                         }
02445                         block_size = lp_block_size(snum);
02446                         if (bsize < block_size) {
02447                                 SMB_BIG_UINT factor = block_size/bsize;
02448                                 bsize = block_size;
02449                                 dsize /= factor;
02450                                 dfree /= factor;
02451                         }
02452                         if (bsize > block_size) {
02453                                 SMB_BIG_UINT factor = bsize/block_size;
02454                                 bsize = block_size;
02455                                 dsize *= factor;
02456                                 dfree *= factor;
02457                         }
02458                         bytes_per_sector = 512;
02459                         sectors_per_unit = bsize/bytes_per_sector;
02460                         DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_FS_FULL_SIZE_INFO bsize=%u, cSectorUnit=%u, \
02461 cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned int)sectors_per_unit,
02462                                 (unsigned int)bytes_per_sector, (unsigned int)dsize, (unsigned int)dfree));
02463                         SBIG_UINT(pdata,0,dsize); /* Total Allocation units. */
02464                         SBIG_UINT(pdata,8,dfree); /* Caller available allocation units. */
02465                         SBIG_UINT(pdata,16,dfree); /* Actual available allocation units. */
02466                         SIVAL(pdata,24,sectors_per_unit); /* Sectors per allocation unit. */
02467                         SIVAL(pdata,28,bytes_per_sector); /* Bytes per sector. */
02468                         break;
02469                 }
02470 
02471                 case SMB_QUERY_FS_DEVICE_INFO:
02472                 case SMB_FS_DEVICE_INFORMATION:
02473                         data_len = 8;
02474                         SIVAL(pdata,0,0); /* dev type */
02475                         SIVAL(pdata,4,0); /* characteristics */
02476                         break;
02477 
02478 #ifdef HAVE_SYS_QUOTAS
02479                 case SMB_FS_QUOTA_INFORMATION:
02480                 /* 
02481                  * what we have to send --metze:
02482                  *
02483                  * Unknown1:            24 NULL bytes
02484                  * Soft Quota Treshold: 8 bytes seems like SMB_BIG_UINT or so
02485                  * Hard Quota Limit:    8 bytes seems like SMB_BIG_UINT or so
02486                  * Quota Flags:         2 byte :
02487                  * Unknown3:            6 NULL bytes
02488                  *
02489                  * 48 bytes total
02490                  * 
02491                  * details for Quota Flags:
02492                  * 
02493                  * 0x0020 Log Limit: log if the user exceeds his Hard Quota
02494                  * 0x0010 Log Warn:  log if the user exceeds his Soft Quota
02495                  * 0x0002 Deny Disk: deny disk access when the user exceeds his Hard Quota
02496                  * 0x0001 Enable Quotas: enable quota for this fs
02497                  *
02498                  */
02499                 {
02500                         /* we need to fake up a fsp here,
02501                          * because its not send in this call
02502                          */
02503                         files_struct fsp;
02504                         SMB_NTQUOTA_STRUCT quotas;
02505                         
02506                         ZERO_STRUCT(fsp);
02507                         ZERO_STRUCT(quotas);
02508                         
02509                         fsp.conn = conn;
02510                         fsp.fnum = -1;
02511                         
02512                         /* access check */
02513                         if (current_user.ut.uid != 0) {
02514                                 DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
02515                                         lp_servicename(SNUM(conn)),conn->user));
02516                                 return ERROR_DOS(ERRDOS,ERRnoaccess);
02517                         }
02518                         
02519                         if (vfs_get_ntquota(&fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
02520                                 DEBUG(0,("vfs_get_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
02521                                 return ERROR_DOS(ERRSRV,ERRerror);
02522                         }
02523 
02524                         data_len = 48;
02525 
02526                         DEBUG(10,("SMB_FS_QUOTA_INFORMATION: for service [%s]\n",lp_servicename(SNUM(conn))));          
02527                 
02528                         /* Unknown1 24 NULL bytes*/
02529                         SBIG_UINT(pdata,0,(SMB_BIG_UINT)0);
02530                         SBIG_UINT(pdata,8,(SMB_BIG_UINT)0);
02531                         SBIG_UINT(pdata,16,(SMB_BIG_UINT)0);
02532                 
02533                         /* Default Soft Quota 8 bytes */
02534                         SBIG_UINT(pdata,24,quotas.softlim);
02535 
02536                         /* Default Hard Quota 8 bytes */
02537                         SBIG_UINT(pdata,32,quotas.hardlim);
02538         
02539                         /* Quota flag 2 bytes */
02540                         SSVAL(pdata,40,quotas.qflags);
02541                 
02542                         /* Unknown3 6 NULL bytes */
02543                         SSVAL(pdata,42,0);
02544                         SIVAL(pdata,44,0);
02545                         
02546                         break;
02547                 }
02548 #endif /* HAVE_SYS_QUOTAS */
02549                 case SMB_FS_OBJECTID_INFORMATION:
02550                 {
02551                         /*
02552                          * No object id, but we transmit version information.
02553                          */
02554                         struct smb_extended_info extended_info;
02555                         samba_extended_info_version (&extended_info);
02556                         SIVAL(pdata,16,extended_info.samba_magic);
02557                         SIVAL(pdata,20,extended_info.samba_version);
02558                         SIVAL(pdata,24,extended_info.samba_subversion);
02559                         SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
02560                         memcpy(pdata+36,extended_info.samba_version_string,28);
02561                         data_len = 64;
02562                         break;
02563                 }
02564 
02565                 /*
02566                  * Query the version and capabilities of the CIFS UNIX extensions
02567                  * in use.
02568                  */
02569 
02570                 case SMB_QUERY_CIFS_UNIX_INFO:
02571                         if (!lp_unix_extensions()) {
02572                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02573                         }
02574                         data_len = 12;
02575                         SSVAL(pdata,0,CIFS_UNIX_MAJOR_VERSION);
02576                         SSVAL(pdata,2,CIFS_UNIX_MINOR_VERSION);
02577                         /* We have POSIX ACLs, pathname and locking capability. */
02578                         SBIG_UINT(pdata,4,((SMB_BIG_UINT)(
02579                                         CIFS_UNIX_POSIX_ACLS_CAP|
02580                                         CIFS_UNIX_POSIX_PATHNAMES_CAP|
02581                                         CIFS_UNIX_FCNTL_LOCKS_CAP|
02582                                         CIFS_UNIX_EXTATTR_CAP|
02583                                         CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)));
02584                         break;
02585 
02586                 case SMB_QUERY_POSIX_FS_INFO:
02587                 {
02588                         int rc;
02589                         vfs_statvfs_struct svfs;
02590 
02591                         if (!lp_unix_extensions()) {
02592                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02593                         }
02594 
02595                         rc = SMB_VFS_STATVFS(conn, ".", &svfs);
02596 
02597                         if (!rc) {
02598                                 data_len = 56;
02599                                 SIVAL(pdata,0,svfs.OptimalTransferSize);
02600                                 SIVAL(pdata,4,svfs.BlockSize);
02601                                 SBIG_UINT(pdata,8,svfs.TotalBlocks);
02602                                 SBIG_UINT(pdata,16,svfs.BlocksAvail);
02603                                 SBIG_UINT(pdata,24,svfs.UserBlocksAvail);
02604                                 SBIG_UINT(pdata,32,svfs.TotalFileNodes);
02605                                 SBIG_UINT(pdata,40,svfs.FreeFileNodes);
02606                                 SBIG_UINT(pdata,48,svfs.FsIdentifier);
02607                                 DEBUG(5,("call_trans2qfsinfo : SMB_QUERY_POSIX_FS_INFO succsessful\n"));
02608 #ifdef EOPNOTSUPP
02609                         } else if (rc == EOPNOTSUPP) {
02610                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02611 #endif /* EOPNOTSUPP */
02612                         } else {
02613                                 DEBUG(0,("vfs_statvfs() failed for service [%s]\n",lp_servicename(SNUM(conn))));
02614                                 return ERROR_DOS(ERRSRV,ERRerror);
02615                         }
02616                         break;
02617                 }
02618 
02619                 case SMB_QUERY_POSIX_WHOAMI:
02620                 {
02621                         uint32_t flags = 0;
02622                         uint32_t sid_bytes;
02623                         int i;
02624 
02625                         if (!lp_unix_extensions()) {
02626                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02627                         }
02628 
02629                         if (max_data_bytes < 40) {
02630                                 return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL);
02631                         }
02632 
02633                         /* We ARE guest if global_sid_Builtin_Guests is
02634                          * in our list of SIDs.
02635                          */
02636                         if (nt_token_check_sid(&global_sid_Builtin_Guests,
02637                                     current_user.nt_user_token)) {
02638                                 flags |= SMB_WHOAMI_GUEST;
02639                         }
02640 
02641                         /* We are NOT guest if global_sid_Authenticated_Users
02642                          * is in our list of SIDs.
02643                          */
02644                         if (nt_token_check_sid(&global_sid_Authenticated_Users,
02645                                     current_user.nt_user_token)) {
02646                                 flags &= ~SMB_WHOAMI_GUEST;
02647                         }
02648 
02649                         /* NOTE: 8 bytes for UID/GID, irrespective of native
02650                          * platform size. This matches
02651                          * SMB_QUERY_FILE_UNIX_BASIC and friends.
02652                          */
02653                         data_len = 4 /* flags */
02654                             + 4 /* flag mask */
02655                             + 8 /* uid */
02656                             + 8 /* gid */
02657                             + 4 /* ngroups */
02658                             + 4 /* num_sids */
02659                             + 4 /* SID bytes */
02660                             + 4 /* pad/reserved */
02661                             + (current_user.ut.ngroups * 8)
02662                                 /* groups list */
02663                             + (current_user.nt_user_token->num_sids *
02664                                     SID_MAX_SIZE)
02665                                 /* SID list */;
02666 
02667                         SIVAL(pdata, 0, flags);
02668                         SIVAL(pdata, 4, SMB_WHOAMI_MASK);
02669                         SBIG_UINT(pdata, 8, (SMB_BIG_UINT)current_user.ut.uid);
02670                         SBIG_UINT(pdata, 16, (SMB_BIG_UINT)current_user.ut.gid);
02671 
02672 
02673                         if (data_len >= max_data_bytes) {
02674                                 /* Potential overflow, skip the GIDs and SIDs. */
02675 
02676                                 SIVAL(pdata, 24, 0); /* num_groups */
02677                                 SIVAL(pdata, 28, 0); /* num_sids */
02678                                 SIVAL(pdata, 32, 0); /* num_sid_bytes */
02679                                 SIVAL(pdata, 36, 0); /* reserved */
02680 
02681                                 data_len = 40;
02682                                 break;
02683                         }
02684 
02685                         SIVAL(pdata, 24, current_user.ut.ngroups);
02686                         SIVAL(pdata, 28,
02687                                 current_user.nt_user_token->num_sids);
02688 
02689                         /* We walk the SID list twice, but this call is fairly
02690                          * infrequent, and I don't expect that it's performance
02691                          * sensitive -- jpeach
02692                          */
02693                         for (i = 0, sid_bytes = 0;
02694                             i < current_user.nt_user_token->num_sids; ++i) {
02695                                 sid_bytes +=
02696                                     sid_size(&current_user.nt_user_token->user_sids[i]);
02697                         }
02698 
02699                         /* SID list byte count */
02700                         SIVAL(pdata, 32, sid_bytes);
02701 
02702                         /* 4 bytes pad/reserved - must be zero */
02703                         SIVAL(pdata, 36, 0);
02704                         data_len = 40;
02705 
02706                         /* GID list */
02707                         for (i = 0; i < current_user.ut.ngroups; ++i) {
02708                                 SBIG_UINT(pdata, data_len,
02709                                         (SMB_BIG_UINT)current_user.ut.groups[i]);
02710                                 data_len += 8;
02711                         }
02712 
02713                         /* SID list */
02714                         for (i = 0;
02715                             i < current_user.nt_user_token->num_sids; ++i) {
02716                                 int sid_len =
02717                                     sid_size(&current_user.nt_user_token->user_sids[i]);
02718 
02719                                 sid_linearize(pdata + data_len, sid_len,
02720                                     &current_user.nt_user_token->user_sids[i]);
02721                                 data_len += sid_len;
02722                         }
02723 
02724                         break;
02725                 }
02726 
02727                 case SMB_MAC_QUERY_FS_INFO:
02728                         /*
02729                          * Thursby MAC extension... ONLY on NTFS filesystems
02730                          * once we do streams then we don't need this
02731                          */
02732                         if (strequal(lp_fstype(SNUM(conn)),"NTFS")) {
02733                                 data_len = 88;
02734                                 SIVAL(pdata,84,0x100); /* Don't support mac... */
02735                                 break;
02736                         }
02737                         /* drop through */
02738                 default:
02739                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02740         }
02741 
02742 
02743         send_trans2_replies( outbuf, bufsize, params, 0, pdata, data_len, max_data_bytes);
02744 
02745         DEBUG( 4, ( "%s info_level = %d\n", smb_fn_name(CVAL(inbuf,smb_com)), info_level) );
02746 
02747         return -1;
02748 }
02749 
02750 /****************************************************************************
02751  Reply to a TRANS2_SETFSINFO (set filesystem info).
02752 ****************************************************************************/
02753 
02754 static int call_trans2setfsinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
02755                                         char **pparams, int total_params, char **ppdata, int total_data,
02756                                         unsigned int max_data_bytes)
02757 {
02758         char *pdata = *ppdata;
02759         char *params = *pparams;
02760         uint16 info_level;
02761         int outsize;
02762 
02763         DEBUG(10,("call_trans2setfsinfo: for service [%s]\n",lp_servicename(SNUM(conn))));
02764 
02765         /*  */
02766         if (total_params < 4) {
02767                 DEBUG(0,("call_trans2setfsinfo: requires total_params(%d) >= 4 bytes!\n",
02768                         total_params));
02769                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02770         }
02771 
02772         info_level = SVAL(params,2);
02773 
02774         switch(info_level) {
02775                 case SMB_SET_CIFS_UNIX_INFO:
02776                         {
02777                                 uint16 client_unix_major;
02778                                 uint16 client_unix_minor;
02779                                 uint32 client_unix_cap_low;
02780                                 uint32 client_unix_cap_high;
02781 
02782                                 if (!lp_unix_extensions()) {
02783                                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02784                                 }
02785 
02786                                 /* There should be 12 bytes of capabilities set. */
02787                                 if (total_data < 8) {
02788                                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02789                                 }
02790                                 client_unix_major = SVAL(pdata,0);
02791                                 client_unix_minor = SVAL(pdata,2);
02792                                 client_unix_cap_low = IVAL(pdata,4);
02793                                 client_unix_cap_high = IVAL(pdata,8);
02794                                 /* Just print these values for now. */
02795                                 DEBUG(10,("call_trans2setfsinfo: set unix info. major = %u, minor = %u \
02796 cap_low = 0x%x, cap_high = 0x%x\n",
02797                                         (unsigned int)client_unix_major,
02798                                         (unsigned int)client_unix_minor,
02799                                         (unsigned int)client_unix_cap_low,
02800                                         (unsigned int)client_unix_cap_high ));
02801 
02802                                 /* Here is where we must switch to posix pathname processing... */
02803                                 if (client_unix_cap_low & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
02804                                         lp_set_posix_pathnames();
02805                                         mangle_change_to_posix();
02806                                 }
02807 
02808                                 if ((client_unix_cap_low & CIFS_UNIX_FCNTL_LOCKS_CAP) &&
02809                                     !(client_unix_cap_low & CIFS_UNIX_POSIX_PATH_OPERATIONS_CAP)) {
02810                                         /* Client that knows how to do posix locks,
02811                                          * but not posix open/mkdir operations. Set a
02812                                          * default type for read/write checks. */
02813 
02814                                         lp_set_posix_default_cifsx_readwrite_locktype(POSIX_LOCK);
02815 
02816                                 }
02817                                 break;
02818                         }
02819                 case SMB_FS_QUOTA_INFORMATION:
02820                         {
02821                                 files_struct *fsp = NULL;
02822                                 SMB_NTQUOTA_STRUCT quotas;
02823         
02824                                 ZERO_STRUCT(quotas);
02825 
02826                                 /* access check */
02827                                 if ((current_user.ut.uid != 0)||!CAN_WRITE(conn)) {
02828                                         DEBUG(0,("set_user_quota: access_denied service [%s] user [%s]\n",
02829                                                 lp_servicename(SNUM(conn)),conn->user));
02830                                         return ERROR_DOS(ERRSRV,ERRaccess);
02831                                 }
02832 
02833                                 /* note: normaly there're 48 bytes,
02834                                  * but we didn't use the last 6 bytes for now 
02835                                  * --metze 
02836                                  */
02837                                 fsp = file_fsp(params,0);
02838                                 if (!CHECK_NTQUOTA_HANDLE_OK(fsp,conn)) {
02839                                         DEBUG(3,("TRANSACT_GET_USER_QUOTA: no valid QUOTA HANDLE\n"));
02840                                         return ERROR_NT(NT_STATUS_INVALID_HANDLE);
02841                                 }
02842 
02843                                 if (total_data < 42) {
02844                                         DEBUG(0,("call_trans2setfsinfo: SET_FS_QUOTA: requires total_data(%d) >= 42 bytes!\n",
02845                                                 total_data));
02846                                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02847                                 }
02848                         
02849                                 /* unknown_1 24 NULL bytes in pdata*/
02850                 
02851                                 /* the soft quotas 8 bytes (SMB_BIG_UINT)*/
02852                                 quotas.softlim = (SMB_BIG_UINT)IVAL(pdata,24);
02853 #ifdef LARGE_SMB_OFF_T
02854                                 quotas.softlim |= (((SMB_BIG_UINT)IVAL(pdata,28)) << 32);
02855 #else /* LARGE_SMB_OFF_T */
02856                                 if ((IVAL(pdata,28) != 0)&&
02857                                         ((quotas.softlim != 0xFFFFFFFF)||
02858                                         (IVAL(pdata,28)!=0xFFFFFFFF))) {
02859                                         /* more than 32 bits? */
02860                                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02861                                 }
02862 #endif /* LARGE_SMB_OFF_T */
02863                 
02864                                 /* the hard quotas 8 bytes (SMB_BIG_UINT)*/
02865                                 quotas.hardlim = (SMB_BIG_UINT)IVAL(pdata,32);
02866 #ifdef LARGE_SMB_OFF_T
02867                                 quotas.hardlim |= (((SMB_BIG_UINT)IVAL(pdata,36)) << 32);
02868 #else /* LARGE_SMB_OFF_T */
02869                                 if ((IVAL(pdata,36) != 0)&&
02870                                         ((quotas.hardlim != 0xFFFFFFFF)||
02871                                         (IVAL(pdata,36)!=0xFFFFFFFF))) {
02872                                         /* more than 32 bits? */
02873                                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02874                                 }
02875 #endif /* LARGE_SMB_OFF_T */
02876                 
02877                                 /* quota_flags 2 bytes **/
02878                                 quotas.qflags = SVAL(pdata,40);
02879                 
02880                                 /* unknown_2 6 NULL bytes follow*/
02881                 
02882                                 /* now set the quotas */
02883                                 if (vfs_set_ntquota(fsp, SMB_USER_FS_QUOTA_TYPE, NULL, &quotas)!=0) {
02884                                         DEBUG(0,("vfs_set_ntquota() failed for service [%s]\n",lp_servicename(SNUM(conn))));
02885                                         return ERROR_DOS(ERRSRV,ERRerror);
02886                                 }
02887                         
02888                                 break;
02889                         }
02890                 default:
02891                         DEBUG(3,("call_trans2setfsinfo: unknown level (0x%X) not implemented yet.\n",
02892                                 info_level));
02893                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
02894                         break;
02895         }
02896 
02897         /* 
02898          * sending this reply works fine, 
02899          * but I'm not sure it's the same 
02900          * like windows do...
02901          * --metze
02902          */ 
02903         outsize = set_message(outbuf,10,0,True);
02904 
02905         return outsize;
02906 }
02907 
02908 #if defined(HAVE_POSIX_ACLS)
02909 /****************************************************************************
02910  Utility function to count the number of entries in a POSIX acl.
02911 ****************************************************************************/
02912 
02913 static unsigned int count_acl_entries(connection_struct *conn, SMB_ACL_T posix_acl)
02914 {
02915         unsigned int ace_count = 0;
02916         int entry_id = SMB_ACL_FIRST_ENTRY;
02917         SMB_ACL_ENTRY_T entry;
02918 
02919         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
02920                 /* get_next... */
02921                 if (entry_id == SMB_ACL_FIRST_ENTRY) {
02922                         entry_id = SMB_ACL_NEXT_ENTRY;
02923                 }
02924                 ace_count++;
02925         }
02926         return ace_count;
02927 }
02928 
02929 /****************************************************************************
02930  Utility function to marshall a POSIX acl into wire format.
02931 ****************************************************************************/
02932 
02933 static BOOL marshall_posix_acl(connection_struct *conn, char *pdata, SMB_STRUCT_STAT *pst, SMB_ACL_T posix_acl)
02934 {
02935         int entry_id = SMB_ACL_FIRST_ENTRY;
02936         SMB_ACL_ENTRY_T entry;
02937 
02938         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
02939                 SMB_ACL_TAG_T tagtype;
02940                 SMB_ACL_PERMSET_T permset;
02941                 unsigned char perms = 0;
02942                 unsigned int own_grp;
02943 
02944                 /* get_next... */
02945                 if (entry_id == SMB_ACL_FIRST_ENTRY) {
02946                         entry_id = SMB_ACL_NEXT_ENTRY;
02947                 }
02948 
02949                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
02950                         DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_TAG_TYPE failed.\n"));
02951                         return False;
02952                 }
02953 
02954                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
02955                         DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_PERMSET failed.\n"));
02956                         return False;
02957                 }
02958 
02959                 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? SMB_POSIX_ACL_READ : 0);
02960                 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? SMB_POSIX_ACL_WRITE : 0);
02961                 perms |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? SMB_POSIX_ACL_EXECUTE : 0);
02962 
02963                 SCVAL(pdata,1,perms);
02964 
02965                 switch (tagtype) {
02966                         case SMB_ACL_USER_OBJ:
02967                                 SCVAL(pdata,0,SMB_POSIX_ACL_USER_OBJ);
02968                                 own_grp = (unsigned int)pst->st_uid;
02969                                 SIVAL(pdata,2,own_grp);
02970                                 SIVAL(pdata,6,0);
02971                                 break;
02972                         case SMB_ACL_USER:
02973                                 {
02974                                         uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
02975                                         if (!puid) {
02976                                                 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
02977                                         }
02978                                         own_grp = (unsigned int)*puid;
02979                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
02980                                         SCVAL(pdata,0,SMB_POSIX_ACL_USER);
02981                                         SIVAL(pdata,2,own_grp);
02982                                         SIVAL(pdata,6,0);
02983                                         break;
02984                                 }
02985                         case SMB_ACL_GROUP_OBJ:
02986                                 SCVAL(pdata,0,SMB_POSIX_ACL_GROUP_OBJ);
02987                                 own_grp = (unsigned int)pst->st_gid;
02988                                 SIVAL(pdata,2,own_grp);
02989                                 SIVAL(pdata,6,0);
02990                                 break;
02991                         case SMB_ACL_GROUP:
02992                                 {
02993                                         gid_t *pgid= (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
02994                                         if (!pgid) {
02995                                                 DEBUG(0,("marshall_posix_acl: SMB_VFS_SYS_ACL_GET_QUALIFIER failed.\n"));
02996                                         }
02997                                         own_grp = (unsigned int)*pgid;
02998                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
02999                                         SCVAL(pdata,0,SMB_POSIX_ACL_GROUP);
03000                                         SIVAL(pdata,2,own_grp);
03001                                         SIVAL(pdata,6,0);
03002                                         break;
03003                                 }
03004                         case SMB_ACL_MASK:
03005                                 SCVAL(pdata,0,SMB_POSIX_ACL_MASK);
03006                                 SIVAL(pdata,2,0xFFFFFFFF);
03007                                 SIVAL(pdata,6,0xFFFFFFFF);
03008                                 break;
03009                         case SMB_ACL_OTHER:
03010                                 SCVAL(pdata,0,SMB_POSIX_ACL_OTHER);
03011                                 SIVAL(pdata,2,0xFFFFFFFF);
03012                                 SIVAL(pdata,6,0xFFFFFFFF);
03013                                 break;
03014                         default:
03015                                 DEBUG(0,("marshall_posix_acl: unknown tagtype.\n"));
03016                                 return False;
03017                 }
03018                 pdata += SMB_POSIX_ACL_ENTRY_SIZE;
03019         }
03020 
03021         return True;
03022 }
03023 #endif
03024 
03025 /****************************************************************************
03026  Store the FILE_UNIX_BASIC info.
03027 ****************************************************************************/
03028 
03029 static char *store_file_unix_basic(connection_struct *conn,
03030                                 char *pdata,
03031                                 files_struct *fsp,
03032                                 const SMB_STRUCT_STAT *psbuf)
03033 {
03034         DEBUG(10,("store_file_unix_basic: SMB_QUERY_FILE_UNIX_BASIC\n"));
03035         DEBUG(4,("store_file_unix_basic: st_mode=%o\n",(int)psbuf->st_mode));
03036 
03037         SOFF_T(pdata,0,get_file_size(*psbuf));             /* File size 64 Bit */
03038         pdata += 8;
03039 
03040         SOFF_T(pdata,0,get_allocation_size(conn,fsp,psbuf)); /* Number of bytes used on disk - 64 Bit */
03041         pdata += 8;
03042 
03043         put_long_date_timespec(pdata,get_ctimespec(psbuf));       /* Change Time 64 Bit */
03044         put_long_date_timespec(pdata+8,get_atimespec(psbuf));     /* Last access time 64 Bit */
03045         put_long_date_timespec(pdata+16,get_mtimespec(psbuf));    /* Last modification time 64 Bit */
03046         pdata += 24;
03047 
03048         SIVAL(pdata,0,psbuf->st_uid);               /* user id for the owner */
03049         SIVAL(pdata,4,0);
03050         pdata += 8;
03051 
03052         SIVAL(pdata,0,psbuf->st_gid);               /* group id of owner */
03053         SIVAL(pdata,4,0);
03054         pdata += 8;
03055 
03056         SIVAL(pdata,0,unix_filetype(psbuf->st_mode));
03057         pdata += 4;
03058 
03059         SIVAL(pdata,0,unix_dev_major(psbuf->st_rdev));   /* Major device number if type is device */
03060         SIVAL(pdata,4,0);
03061         pdata += 8;
03062 
03063         SIVAL(pdata,0,unix_dev_minor(psbuf->st_rdev));   /* Minor device number if type is device */
03064         SIVAL(pdata,4,0);
03065         pdata += 8;
03066 
03067         SINO_T_VAL(pdata,0,(SMB_INO_T)psbuf->st_ino);   /* inode number */
03068         pdata += 8;
03069                                 
03070         SIVAL(pdata,0, unix_perms_to_wire(psbuf->st_mode));     /* Standard UNIX file permissions */
03071         SIVAL(pdata,4,0);
03072         pdata += 8;
03073 
03074         SIVAL(pdata,0,psbuf->st_nlink);             /* number of hard links */
03075         SIVAL(pdata,4,0);
03076         pdata += 8;
03077 
03078         return pdata;
03079 }
03080 
03081 /* Forward and reverse mappings from the UNIX_INFO2 file flags field and
03082  * the chflags(2) (or equivalent) flags.
03083  *
03084  * XXX: this really should be behind the VFS interface. To do this, we would
03085  * need to alter SMB_STRUCT_STAT so that it included a flags and a mask field.
03086  * Each VFS module could then implement it's own mapping as appropriate for the
03087  * platform. We would then pass the SMB flags into SMB_VFS_CHFLAGS.
03088  */
03089 static const struct {unsigned stat_fflag; unsigned smb_fflag;}
03090         info2_flags_map[] =
03091 {
03092 #ifdef UF_NODUMP
03093     { UF_NODUMP, EXT_DO_NOT_BACKUP },
03094 #endif
03095 
03096 #ifdef UF_IMMUTABLE
03097     { UF_IMMUTABLE, EXT_IMMUTABLE },
03098 #endif
03099 
03100 #ifdef UF_APPEND
03101     { UF_APPEND, EXT_OPEN_APPEND_ONLY },
03102 #endif
03103 
03104 #ifdef UF_HIDDEN
03105     { UF_HIDDEN, EXT_HIDDEN },
03106 #endif
03107 
03108     /* Do not remove. We need to guarantee that this array has at least one
03109      * entry to build on HP-UX.
03110      */
03111     { 0, 0 }
03112 
03113 };
03114 
03115 static void map_info2_flags_from_sbuf(const SMB_STRUCT_STAT *psbuf,
03116                                 uint32 *smb_fflags, uint32 *smb_fmask)
03117 {
03118 #ifdef HAVE_STAT_ST_FLAGS
03119         int i;
03120 
03121         for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
03122             *smb_fmask |= info2_flags_map[i].smb_fflag;
03123             if (psbuf->st_flags & info2_flags_map[i].stat_fflag) {
03124                     *smb_fflags |= info2_flags_map[i].smb_fflag;
03125             }
03126         }
03127 #endif /* HAVE_STAT_ST_FLAGS */
03128 }
03129 
03130 static BOOL map_info2_flags_to_sbuf(const SMB_STRUCT_STAT *psbuf,
03131                                 const uint32 smb_fflags,
03132                                 const uint32 smb_fmask,
03133                                 int *stat_fflags)
03134 {
03135 #ifdef HAVE_STAT_ST_FLAGS
03136         uint32 max_fmask = 0;
03137         int i;
03138 
03139         *stat_fflags = psbuf->st_flags;
03140 
03141         /* For each flags requested in smb_fmask, check the state of the
03142          * corresponding flag in smb_fflags and set or clear the matching
03143          * stat flag.
03144          */
03145 
03146         for (i = 0; i < ARRAY_SIZE(info2_flags_map); ++i) {
03147             max_fmask |= info2_flags_map[i].smb_fflag;
03148             if (smb_fmask & info2_flags_map[i].smb_fflag) {
03149                     if (smb_fflags & info2_flags_map[i].smb_fflag) {
03150                             *stat_fflags |= info2_flags_map[i].stat_fflag;
03151                     } else {
03152                             *stat_fflags &= ~info2_flags_map[i].stat_fflag;
03153                     }
03154             }
03155         }
03156 
03157         /* If smb_fmask is asking to set any bits that are not supported by
03158          * our flag mappings, we should fail.
03159          */
03160         if ((smb_fmask & max_fmask) != smb_fmask) {
03161                 return False;
03162         }
03163 
03164         return True;
03165 #else
03166         return False;
03167 #endif /* HAVE_STAT_ST_FLAGS */
03168 }
03169 
03170 
03171 /* Just like SMB_QUERY_FILE_UNIX_BASIC, but with the addition
03172  * of file flags and birth (create) time.
03173  */
03174 static char *store_file_unix_basic_info2(connection_struct *conn,
03175                                 char *pdata,
03176                                 files_struct *fsp,
03177                                 const SMB_STRUCT_STAT *psbuf)
03178 {
03179         uint32 file_flags = 0;
03180         uint32 flags_mask = 0;
03181 
03182         pdata = store_file_unix_basic(conn, pdata, fsp, psbuf);
03183 
03184         /* Create (birth) time 64 bit */
03185         put_long_date_timespec(pdata, get_create_timespec(psbuf, False));
03186         pdata += 8;
03187 
03188         map_info2_flags_from_sbuf(psbuf, &file_flags, &flags_mask);
03189         SIVAL(pdata, 0, file_flags); /* flags */
03190         SIVAL(pdata, 4, flags_mask); /* mask */
03191         pdata += 8;
03192 
03193         return pdata;
03194 }
03195 
03196 /****************************************************************************
03197  Reply to a TRANS2_QFILEPATHINFO or TRANSACT2_QFILEINFO (query file info by
03198  file name or file id).
03199 ****************************************************************************/
03200 
03201 static int call_trans2qfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
03202                                         unsigned int tran_call,
03203                                         char **pparams, int total_params, char **ppdata, int total_data,
03204                                         unsigned int max_data_bytes)
03205 {
03206         char *params = *pparams;
03207         char *pdata = *ppdata;
03208         uint16 info_level;
03209         int mode=0;
03210         int nlink;
03211         SMB_OFF_T file_size=0;
03212         SMB_BIG_UINT allocation_size=0;
03213         unsigned int data_size = 0;
03214         unsigned int param_size = 2;
03215         SMB_STRUCT_STAT sbuf;
03216         pstring fname, dos_fname;
03217         char *fullpathname;
03218         char *base_name;
03219         char *p;
03220         SMB_OFF_T pos = 0;
03221         BOOL delete_pending = False;
03222         int len;
03223         time_t create_time, mtime, atime;
03224         struct timespec create_time_ts, mtime_ts, atime_ts;
03225         files_struct *fsp = NULL;
03226         TALLOC_CTX *data_ctx = NULL;
03227         struct ea_list *ea_list = NULL;
03228         uint32 access_mask = 0x12019F; /* Default - GENERIC_EXECUTE mapping from Windows */
03229         char *lock_data = NULL;
03230 
03231         if (!params)
03232                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03233 
03234         ZERO_STRUCT(sbuf);
03235 
03236         if (tran_call == TRANSACT2_QFILEINFO) {
03237                 if (total_params < 4) {
03238                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03239                 }
03240 
03241                 fsp = file_fsp(params,0);
03242                 info_level = SVAL(params,2);
03243 
03244                 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level));
03245 
03246                 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
03247                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
03248                 }
03249 
03250                 if(fsp && (fsp->fake_file_handle)) {
03251                         /*
03252                          * This is actually for the QUOTA_FAKE_FILE --metze
03253                          */
03254                                                 
03255                         pstrcpy(fname, fsp->fsp_name);
03256                         /* We know this name is ok, it's already passed the checks. */
03257                         
03258                 } else if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) {
03259                         /*
03260                          * This is actually a QFILEINFO on a directory
03261                          * handle (returned from an NT SMB). NT5.0 seems
03262                          * to do this call. JRA.
03263                          */
03264                         /* We know this name is ok, it's already passed the checks. */
03265                         pstrcpy(fname, fsp->fsp_name);
03266                   
03267                         if (INFO_LEVEL_IS_UNIX(info_level)) {
03268                                 /* Always do lstat for UNIX calls. */
03269                                 if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
03270                                         DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
03271                                         return UNIXERROR(ERRDOS,ERRbadpath);
03272                                 }
03273                         } else if (SMB_VFS_STAT(conn,fname,&sbuf)) {
03274                                 DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
03275                                 return UNIXERROR(ERRDOS,ERRbadpath);
03276                         }
03277 
03278                         delete_pending = get_delete_on_close_flag(sbuf.st_dev, sbuf.st_ino);
03279                 } else {
03280                         /*
03281                          * Original code - this is an open file.
03282                          */
03283                         CHECK_FSP(fsp,conn);
03284 
03285                         pstrcpy(fname, fsp->fsp_name);
03286                         if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) {
03287                                 DEBUG(3,("fstat of fnum %d failed (%s)\n", fsp->fnum, strerror(errno)));
03288                                 return(UNIXERROR(ERRDOS,ERRbadfid));
03289                         }
03290                         pos = fsp->fh->position_information;
03291                         delete_pending = get_delete_on_close_flag(sbuf.st_dev, sbuf.st_ino);
03292                         access_mask = fsp->access_mask;
03293                 }
03294         } else {
03295                 NTSTATUS status = NT_STATUS_OK;
03296 
03297                 /* qpathinfo */
03298                 if (total_params < 7) {
03299                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03300                 }
03301 
03302                 info_level = SVAL(params,0);
03303 
03304                 DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level));
03305 
03306                 if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
03307                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
03308                 }
03309 
03310                 srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), total_params - 6, STR_TERMINATE, &status);
03311                 if (!NT_STATUS_IS_OK(status)) {
03312                         return ERROR_NT(status);
03313                 }
03314 
03315                 status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
03316                 if (!NT_STATUS_IS_OK(status)) {
03317                         if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
03318                                 return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
03319                         }
03320                         return ERROR_NT(status);
03321                 }
03322 
03323                 status = unix_convert(conn, fname, False, NULL, &sbuf);
03324                 if (!NT_STATUS_IS_OK(status)) {
03325                         return ERROR_NT(status);
03326                 }
03327                 status = check_name(conn, fname);
03328                 if (!NT_STATUS_IS_OK(status)) {
03329                         DEBUG(3,("call_trans2qfilepathinfo: fileinfo of %s failed (%s)\n",fname,nt_errstr(status)));
03330                         return ERROR_NT(status);
03331                 }
03332 
03333                 if (INFO_LEVEL_IS_UNIX(info_level)) {
03334                         /* Always do lstat for UNIX calls. */
03335                         if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
03336                                 DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
03337                                 return UNIXERROR(ERRDOS,ERRbadpath);
03338                         }
03339                 } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf) && (info_level != SMB_INFO_IS_NAME_VALID)) {
03340                         DEBUG(3,("call_trans2qfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
03341                         return UNIXERROR(ERRDOS,ERRbadpath);
03342                 }
03343 
03344                 delete_pending = get_delete_on_close_flag(sbuf.st_dev, sbuf.st_ino);
03345                 if (delete_pending) {
03346                         return ERROR_NT(NT_STATUS_DELETE_PENDING);
03347                 }
03348         }
03349 
03350         if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
03351                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
03352         }
03353 
03354         DEBUG(3,("call_trans2qfilepathinfo %s (fnum = %d) level=%d call=%d total_data=%d\n",
03355                 fname,fsp ? fsp->fnum : -1, info_level,tran_call,total_data));
03356 
03357         p = strrchr_m(fname,'/'); 
03358         if (!p)
03359                 base_name = fname;
03360         else
03361                 base_name = p+1;
03362 
03363         mode = dos_mode(conn,fname,&sbuf);
03364         if (!mode)
03365                 mode = FILE_ATTRIBUTE_NORMAL;
03366 
03367         nlink = sbuf.st_nlink;
03368 
03369         if (nlink && (mode&aDIR)) {
03370                 nlink = 1;
03371         }
03372 
03373         if ((nlink > 0) && delete_pending) {
03374                 nlink -= 1;
03375         }
03376 
03377         fullpathname = fname;
03378         if (!(mode & aDIR))
03379                 file_size = get_file_size(sbuf);
03380 
03381         /* Pull out any data sent here before we realloc. */
03382         switch (info_level) {
03383                 case SMB_INFO_QUERY_EAS_FROM_LIST:
03384                 {
03385                         /* Pull any EA list from the data portion. */
03386                         uint32 ea_size;
03387 
03388                         if (total_data < 4) {
03389                                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03390                         }
03391                         ea_size = IVAL(pdata,0);
03392 
03393                         if (total_data > 0 && ea_size != total_data) {
03394                                 DEBUG(4,("call_trans2qfilepathinfo: Rejecting EA request with incorrect \
03395 total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pdata,0) ));
03396                                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03397                         }
03398 
03399                         if (!lp_ea_support(SNUM(conn))) {
03400                                 return ERROR_DOS(ERRDOS,ERReasnotsupported);
03401                         }
03402 
03403                         if ((data_ctx = talloc_init("ea_list")) == NULL) {
03404                                 return ERROR_NT(NT_STATUS_NO_MEMORY);
03405                         }
03406 
03407                         /* Pull out the list of names. */
03408                         ea_list = read_ea_name_list(data_ctx, pdata + 4, ea_size - 4);
03409                         if (!ea_list) {
03410                                 talloc_destroy(data_ctx);
03411                                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03412                         }
03413                         break;
03414                 }
03415 
03416                 case SMB_QUERY_POSIX_LOCK:
03417                 {
03418                         if (fsp == NULL || fsp->fh->fd == -1) {
03419                                 return ERROR_NT(NT_STATUS_INVALID_HANDLE);
03420                         }
03421 
03422                         if (total_data != POSIX_LOCK_DATA_SIZE) {
03423                                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03424                         }
03425 
03426                         if ((data_ctx = talloc_init("lock_request")) == NULL) {
03427                                 return ERROR_NT(NT_STATUS_NO_MEMORY);
03428                         }
03429 
03430                         /* Copy the lock range data. */
03431                         lock_data = (char *)TALLOC_MEMDUP(
03432                                 data_ctx, pdata, total_data);
03433                         if (!lock_data) {
03434                                 talloc_destroy(data_ctx);
03435                                 return ERROR_NT(NT_STATUS_NO_MEMORY);
03436                         }
03437                 }
03438                 default:
03439                         break;
03440         }
03441 
03442         *pparams = (char *)SMB_REALLOC(*pparams,2);
03443         if (*pparams == NULL) {
03444                 talloc_destroy(data_ctx);
03445                 return ERROR_NT(NT_STATUS_NO_MEMORY);
03446         }
03447         params = *pparams;
03448         SSVAL(params,0,0);
03449         data_size = max_data_bytes + DIR_ENTRY_SAFETY_MARGIN;
03450         *ppdata = (char *)SMB_REALLOC(*ppdata, data_size); 
03451         if (*ppdata == NULL ) {
03452                 talloc_destroy(data_ctx);
03453                 return ERROR_NT(NT_STATUS_NO_MEMORY);
03454         }
03455         pdata = *ppdata;
03456 
03457         create_time_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
03458         mtime_ts = get_mtimespec(&sbuf);
03459         atime_ts = get_atimespec(&sbuf);
03460 
03461         allocation_size = get_allocation_size(conn,fsp,&sbuf);
03462 
03463         if (fsp) {
03464                 if (!null_timespec(fsp->pending_modtime)) {
03465                         /* the pending modtime overrides the current modtime */
03466                         mtime_ts = fsp->pending_modtime;
03467                 }
03468         } else {
03469                 /* Do we have this path open ? */
03470                 files_struct *fsp1 = file_find_di_first(sbuf.st_dev, sbuf.st_ino);
03471                 if (fsp1 && !null_timespec(fsp1->pending_modtime)) {
03472                         /* the pending modtime overrides the current modtime */
03473                         mtime_ts = fsp1->pending_modtime;
03474                 }
03475                 if (fsp1 && fsp1->initial_allocation_size) {
03476                         allocation_size = get_allocation_size(conn, fsp1, &sbuf);
03477                 }
03478         }
03479 
03480         if (lp_dos_filetime_resolution(SNUM(conn))) {
03481                 dos_filetime_timespec(&create_time_ts);
03482                 dos_filetime_timespec(&mtime_ts);
03483                 dos_filetime_timespec(&atime_ts);
03484         }
03485 
03486         create_time = convert_timespec_to_time_t(create_time_ts);
03487         mtime = convert_timespec_to_time_t(mtime_ts);
03488         atime = convert_timespec_to_time_t(atime_ts);
03489 
03490         /* NT expects the name to be in an exact form of the *full*
03491            filename. See the trans2 torture test */
03492         if (strequal(base_name,".")) {
03493                 pstrcpy(dos_fname, "\\");
03494         } else {
03495                 pstr_sprintf(dos_fname, "\\%s", fname);
03496                 string_replace(dos_fname, '/', '\\');
03497         }
03498 
03499         switch (info_level) {
03500                 case SMB_INFO_STANDARD:
03501                         DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_STANDARD\n"));
03502                         data_size = 22;
03503                         srv_put_dos_date2(pdata,l1_fdateCreation,create_time);
03504                         srv_put_dos_date2(pdata,l1_fdateLastAccess,atime);
03505                         srv_put_dos_date2(pdata,l1_fdateLastWrite,mtime); /* write time */
03506                         SIVAL(pdata,l1_cbFile,(uint32)file_size);
03507                         SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
03508                         SSVAL(pdata,l1_attrFile,mode);
03509                         break;
03510 
03511                 case SMB_INFO_QUERY_EA_SIZE:
03512                 {
03513                         unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
03514                         DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EA_SIZE\n"));
03515                         data_size = 26;
03516                         srv_put_dos_date2(pdata,0,create_time);
03517                         srv_put_dos_date2(pdata,4,atime);
03518                         srv_put_dos_date2(pdata,8,mtime); /* write time */
03519                         SIVAL(pdata,12,(uint32)file_size);
03520                         SIVAL(pdata,16,(uint32)allocation_size);
03521                         SSVAL(pdata,20,mode);
03522                         SIVAL(pdata,22,ea_size);
03523                         break;
03524                 }
03525 
03526                 case SMB_INFO_IS_NAME_VALID:
03527                         DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_IS_NAME_VALID\n"));
03528                         if (tran_call == TRANSACT2_QFILEINFO) {
03529                                 /* os/2 needs this ? really ?*/      
03530                                 return ERROR_DOS(ERRDOS,ERRbadfunc); 
03531                         }
03532                         data_size = 0;
03533                         param_size = 0;
03534                         break;
03535                         
03536                 case SMB_INFO_QUERY_EAS_FROM_LIST:
03537                 {
03538                         size_t total_ea_len = 0;
03539                         struct ea_list *ea_file_list = NULL;
03540 
03541                         DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_EAS_FROM_LIST\n"));
03542 
03543                         ea_file_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
03544                         ea_list = ea_list_union(ea_list, ea_file_list, &total_ea_len);
03545 
03546                         if (!ea_list || (total_ea_len > data_size)) {
03547                                 talloc_destroy(data_ctx);
03548                                 data_size = 4;
03549                                 SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
03550                                 break;
03551                         }
03552 
03553                         data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
03554                         talloc_destroy(data_ctx);
03555                         break;
03556                 }
03557 
03558                 case SMB_INFO_QUERY_ALL_EAS:
03559                 {
03560                         /* We have data_size bytes to put EA's into. */
03561                         size_t total_ea_len = 0;
03562 
03563                         DEBUG(10,("call_trans2qfilepathinfo: SMB_INFO_QUERY_ALL_EAS\n"));
03564 
03565                         data_ctx = talloc_init("ea_ctx");
03566                         if (!data_ctx) {
03567                                 return ERROR_NT(NT_STATUS_NO_MEMORY);
03568                         }
03569 
03570                         ea_list = get_ea_list_from_file(data_ctx, conn, fsp, fname, &total_ea_len);
03571                         if (!ea_list || (total_ea_len > data_size)) {
03572                                 talloc_destroy(data_ctx);
03573                                 data_size = 4;
03574                                 SIVAL(pdata,0,4);   /* EA List Length must be set to 4 if no EA's. */
03575                                 break;
03576                         }
03577 
03578                         data_size = fill_ea_buffer(data_ctx, pdata, data_size, conn, ea_list);
03579                         talloc_destroy(data_ctx);
03580                         break;
03581                 }
03582 
03583                 case SMB_FILE_BASIC_INFORMATION:
03584                 case SMB_QUERY_FILE_BASIC_INFO:
03585 
03586                         if (info_level == SMB_QUERY_FILE_BASIC_INFO) {
03587                                 DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_BASIC_INFO\n"));
03588                                 data_size = 36; /* w95 returns 40 bytes not 36 - why ?. */
03589                         } else {
03590                                 DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_BASIC_INFORMATION\n"));
03591                                 data_size = 40;
03592                                 SIVAL(pdata,36,0);
03593                         }
03594                         put_long_date_timespec(pdata,create_time_ts);
03595                         put_long_date_timespec(pdata+8,atime_ts);
03596                         put_long_date_timespec(pdata+16,mtime_ts); /* write time */
03597                         put_long_date_timespec(pdata+24,mtime_ts); /* change time */
03598                         SIVAL(pdata,32,mode);
03599 
03600                         DEBUG(5,("SMB_QFBI - "));
03601                         DEBUG(5,("create: %s ", ctime(&create_time)));
03602                         DEBUG(5,("access: %s ", ctime(&atime)));
03603                         DEBUG(5,("write: %s ", ctime(&mtime)));
03604                         DEBUG(5,("change: %s ", ctime(&mtime)));
03605                         DEBUG(5,("mode: %x\n", mode));
03606                         break;
03607 
03608                 case SMB_FILE_STANDARD_INFORMATION:
03609                 case SMB_QUERY_FILE_STANDARD_INFO:
03610 
03611                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STANDARD_INFORMATION\n"));
03612                         data_size = 24;
03613                         SOFF_T(pdata,0,allocation_size);
03614                         SOFF_T(pdata,8,file_size);
03615                         SIVAL(pdata,16,nlink);
03616                         SCVAL(pdata,20,delete_pending?1:0);
03617                         SCVAL(pdata,21,(mode&aDIR)?1:0);
03618                         SSVAL(pdata,22,0); /* Padding. */
03619                         break;
03620 
03621                 case SMB_FILE_EA_INFORMATION:
03622                 case SMB_QUERY_FILE_EA_INFO:
03623                 {
03624                         unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
03625                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_EA_INFORMATION\n"));
03626                         data_size = 4;
03627                         SIVAL(pdata,0,ea_size);
03628                         break;
03629                 }
03630 
03631                 /* Get the 8.3 name - used if NT SMB was negotiated. */
03632                 case SMB_QUERY_FILE_ALT_NAME_INFO:
03633                 case SMB_FILE_ALTERNATE_NAME_INFORMATION:
03634                 {
03635                         pstring short_name;
03636 
03637                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALTERNATE_NAME_INFORMATION\n"));
03638                         pstrcpy(short_name,base_name);
03639                         /* Mangle if not already 8.3 */
03640                         if(!mangle_is_8_3(short_name, True, conn->params)) {
03641                                 mangle_map(short_name,True,True,conn->params);
03642                         }
03643                         len = srvstr_push(outbuf, pdata+4, short_name, max_data_bytes - 4, STR_UNICODE);
03644                         data_size = 4 + len;
03645                         SIVAL(pdata,0,len);
03646                         break;
03647                 }
03648 
03649                 case SMB_QUERY_FILE_NAME_INFO:
03650                         /*
03651                           this must be *exactly* right for ACLs on mapped drives to work
03652                          */
03653                         len = srvstr_push(outbuf, pdata+4, dos_fname, max_data_bytes - 4, STR_UNICODE);
03654                         DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_NAME_INFO\n"));
03655                         data_size = 4 + len;
03656                         SIVAL(pdata,0,len);
03657                         break;
03658 
03659                 case SMB_FILE_ALLOCATION_INFORMATION:
03660                 case SMB_QUERY_FILE_ALLOCATION_INFO:
03661                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALLOCATION_INFORMATION\n"));
03662                         data_size = 8;
03663                         SOFF_T(pdata,0,allocation_size);
03664                         break;
03665 
03666                 case SMB_FILE_END_OF_FILE_INFORMATION:
03667                 case SMB_QUERY_FILE_END_OF_FILEINFO:
03668                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_END_OF_FILE_INFORMATION\n"));
03669                         data_size = 8;
03670                         SOFF_T(pdata,0,file_size);
03671                         break;
03672 
03673                 case SMB_QUERY_FILE_ALL_INFO:
03674                 case SMB_FILE_ALL_INFORMATION:
03675                 {
03676                         unsigned int ea_size = estimate_ea_size(conn, fsp, fname);
03677                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALL_INFORMATION\n"));
03678                         put_long_date_timespec(pdata,create_time_ts);
03679                         put_long_date_timespec(pdata+8,atime_ts);
03680                         put_long_date_timespec(pdata+16,mtime_ts); /* write time */
03681                         put_long_date_timespec(pdata+24,mtime_ts); /* change time */
03682                         SIVAL(pdata,32,mode);
03683                         SIVAL(pdata,36,0); /* padding. */
03684                         pdata += 40;
03685                         SOFF_T(pdata,0,allocation_size);
03686                         SOFF_T(pdata,8,file_size);
03687                         SIVAL(pdata,16,nlink);
03688                         SCVAL(pdata,20,delete_pending);
03689                         SCVAL(pdata,21,(mode&aDIR)?1:0);
03690                         SSVAL(pdata,22,0);
03691                         pdata += 24;
03692                         SIVAL(pdata,0,ea_size);
03693                         pdata += 4; /* EA info */
03694                         len = srvstr_push(outbuf, pdata+4, dos_fname, max_data_bytes - (pdata+4 - *ppdata), STR_UNICODE);
03695                         SIVAL(pdata,0,len);
03696                         pdata += 4 + len;
03697                         data_size = PTR_DIFF(pdata,(*ppdata));
03698                         break;
03699                 }
03700                 case SMB_FILE_INTERNAL_INFORMATION:
03701                         /* This should be an index number - looks like
03702                            dev/ino to me :-) 
03703 
03704                            I think this causes us to fail the IFSKIT
03705                            BasicFileInformationTest. -tpot */
03706 
03707                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_INTERNAL_INFORMATION\n"));
03708                         SIVAL(pdata,0,sbuf.st_ino); /* FileIndexLow */
03709                         SIVAL(pdata,4,sbuf.st_dev); /* FileIndexHigh */
03710                         data_size = 8;
03711                         break;
03712 
03713                 case SMB_FILE_ACCESS_INFORMATION:
03714                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ACCESS_INFORMATION\n"));
03715                         SIVAL(pdata,0,access_mask);
03716                         data_size = 4;
03717                         break;
03718 
03719                 case SMB_FILE_NAME_INFORMATION:
03720                         /* Pathname with leading '\'. */
03721                         {
03722                                 size_t byte_len;
03723                                 byte_len = dos_PutUniCode(pdata+4,dos_fname,(size_t)max_data_bytes,False);
03724                                 DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NAME_INFORMATION\n"));
03725                                 SIVAL(pdata,0,byte_len);
03726                                 data_size = 4 + byte_len;
03727                                 break;
03728                         }
03729 
03730                 case SMB_FILE_DISPOSITION_INFORMATION:
03731                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_DISPOSITION_INFORMATION\n"));
03732                         data_size = 1;
03733                         SCVAL(pdata,0,delete_pending);
03734                         break;
03735 
03736                 case SMB_FILE_POSITION_INFORMATION:
03737                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_POSITION_INFORMATION\n"));
03738                         data_size = 8;
03739                         SOFF_T(pdata,0,pos);
03740                         break;
03741 
03742                 case SMB_FILE_MODE_INFORMATION:
03743                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_MODE_INFORMATION\n"));
03744                         SIVAL(pdata,0,mode);
03745                         data_size = 4;
03746                         break;
03747 
03748                 case SMB_FILE_ALIGNMENT_INFORMATION:
03749                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ALIGNMENT_INFORMATION\n"));
03750                         SIVAL(pdata,0,0); /* No alignment needed. */
03751                         data_size = 4;
03752                         break;
03753 
03754 #if 0
03755                 /*
03756                  * NT4 server just returns "invalid query" to this - if we try to answer
03757                  * it then NTws gets a BSOD! (tridge).
03758                  * W2K seems to want this. JRA.
03759                  */
03760                 case SMB_QUERY_FILE_STREAM_INFO:
03761 #endif
03762                 case SMB_FILE_STREAM_INFORMATION:
03763                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STREAM_INFORMATION\n"));
03764                         if (mode & aDIR) {
03765                                 data_size = 0;
03766                         } else {
03767                                 size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", (size_t)0xE, False);
03768                                 SIVAL(pdata,0,0); /* ??? */
03769                                 SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
03770                                 SOFF_T(pdata,8,file_size);
03771                                 SOFF_T(pdata,16,allocation_size);
03772                                 data_size = 24 + byte_len;
03773                         }
03774                         break;
03775 
03776                 case SMB_QUERY_COMPRESSION_INFO:
03777                 case SMB_FILE_COMPRESSION_INFORMATION:
03778                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
03779                         SOFF_T(pdata,0,file_size);
03780                         SIVAL(pdata,8,0); /* ??? */
03781                         SIVAL(pdata,12,0); /* ??? */
03782                         data_size = 16;
03783                         break;
03784 
03785                 case SMB_FILE_NETWORK_OPEN_INFORMATION:
03786                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_NETWORK_OPEN_INFORMATION\n"));
03787                         put_long_date_timespec(pdata,create_time_ts);
03788                         put_long_date_timespec(pdata+8,atime_ts);
03789                         put_long_date_timespec(pdata+16,mtime_ts); /* write time */
03790                         put_long_date_timespec(pdata+24,mtime_ts); /* change time */
03791                         SOFF_T(pdata,32,allocation_size);
03792                         SOFF_T(pdata,40,file_size);
03793                         SIVAL(pdata,48,mode);
03794                         SIVAL(pdata,52,0); /* ??? */
03795                         data_size = 56;
03796                         break;
03797 
03798                 case SMB_FILE_ATTRIBUTE_TAG_INFORMATION:
03799                         DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_ATTRIBUTE_TAG_INFORMATION\n"));
03800                         SIVAL(pdata,0,mode);
03801                         SIVAL(pdata,4,0);
03802                         data_size = 8;
03803                         break;
03804 
03805                 /*
03806                  * CIFS UNIX Extensions.
03807                  */
03808 
03809                 case SMB_QUERY_FILE_UNIX_BASIC:
03810 
03811                         pdata = store_file_unix_basic(conn, pdata, fsp, &sbuf);
03812                         data_size = PTR_DIFF(pdata,(*ppdata));
03813 
03814                         {
03815                                 int i;
03816                                 DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_BASIC "));
03817 
03818                                 for (i=0; i<100; i++)
03819                                         DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
03820                                 DEBUG(4,("\n"));
03821                         }
03822 
03823                         break;
03824 
03825                 case SMB_QUERY_FILE_UNIX_INFO2:
03826 
03827                         pdata = store_file_unix_basic_info2(conn, pdata, fsp, &sbuf);
03828                         data_size = PTR_DIFF(pdata,(*ppdata));
03829 
03830                         {
03831                                 int i;
03832                                 DEBUG(4,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_INFO2 "));
03833 
03834                                 for (i=0; i<100; i++)
03835                                         DEBUG(4,("%d=%x, ",i, (*ppdata)[i]));
03836                                 DEBUG(4,("\n"));
03837                         }
03838 
03839                         break;
03840 
03841                 case SMB_QUERY_FILE_UNIX_LINK:
03842                         {
03843                                 pstring buffer;
03844 
03845                                 DEBUG(10,("call_trans2qfilepathinfo: SMB_QUERY_FILE_UNIX_LINK\n"));
03846 #ifdef S_ISLNK
03847                                 if(!S_ISLNK(sbuf.st_mode))
03848                                         return(UNIXERROR(ERRSRV,ERRbadlink));
03849 #else
03850                                 return(UNIXERROR(ERRDOS,ERRbadlink));
03851 #endif
03852                                 len = SMB_VFS_READLINK(conn,fullpathname, buffer, sizeof(pstring)-1);     /* read link */
03853                                 if (len == -1)
03854                                         return(UNIXERROR(ERRDOS,ERRnoaccess));
03855                                 buffer[len] = 0;
03856                                 len = srvstr_push(outbuf, pdata, buffer, max_data_bytes, STR_TERMINATE);
03857                                 pdata += len;
03858                                 data_size = PTR_DIFF(pdata,(*ppdata));
03859 
03860                                 break;
03861                         }
03862 
03863 #if defined(HAVE_POSIX_ACLS)
03864                 case SMB_QUERY_POSIX_ACL:
03865                         {
03866                                 SMB_ACL_T file_acl = NULL;
03867                                 SMB_ACL_T def_acl = NULL;
03868                                 uint16 num_file_acls = 0;
03869                                 uint16 num_def_acls = 0;
03870 
03871                                 if (fsp && !fsp->is_directory && (fsp->fh->fd != -1)) {
03872                                         file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
03873                                 } else {
03874                                         file_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
03875                                 }
03876 
03877                                 if (file_acl == NULL && no_acl_syscall_error(errno)) {
03878                                         DEBUG(5,("call_trans2qfilepathinfo: ACLs not implemented on filesystem containing %s\n",
03879                                                 fname ));
03880                                         return ERROR_NT(NT_STATUS_NOT_IMPLEMENTED);
03881                                 }
03882 
03883                                 if (S_ISDIR(sbuf.st_mode)) {
03884                                         if (fsp && fsp->is_directory) {
03885                                                 def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
03886                                         } else {
03887                                                 def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT);
03888                                         }
03889                                         def_acl = free_empty_sys_acl(conn, def_acl);
03890                                 }
03891 
03892                                 num_file_acls = count_acl_entries(conn, file_acl);
03893                                 num_def_acls = count_acl_entries(conn, def_acl);
03894 
03895                                 if ( data_size < (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE) {
03896                                         DEBUG(5,("call_trans2qfilepathinfo: data_size too small (%u) need %u\n",
03897                                                 data_size,
03898                                                 (unsigned int)((num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE +
03899                                                         SMB_POSIX_ACL_HEADER_SIZE) ));
03900                                         if (file_acl) {
03901                                                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
03902                                         }
03903                                         if (def_acl) {
03904                                                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03905                                         }
03906                                         return ERROR_NT(NT_STATUS_BUFFER_TOO_SMALL);
03907                                 }
03908 
03909                                 SSVAL(pdata,0,SMB_POSIX_ACL_VERSION);
03910                                 SSVAL(pdata,2,num_file_acls);
03911                                 SSVAL(pdata,4,num_def_acls);
03912                                 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE, &sbuf, file_acl)) {
03913                                         if (file_acl) {
03914                                                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
03915                                         }
03916                                         if (def_acl) {
03917                                                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03918                                         }
03919                                         return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
03920                                 }
03921                                 if (!marshall_posix_acl(conn, pdata + SMB_POSIX_ACL_HEADER_SIZE + (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE), &sbuf, def_acl)) {
03922                                         if (file_acl) {
03923                                                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
03924                                         }
03925                                         if (def_acl) {
03926                                                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03927                                         }
03928                                         return ERROR_NT(NT_STATUS_INTERNAL_ERROR);
03929                                 }
03930 
03931                                 if (file_acl) {
03932                                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
03933                                 }
03934                                 if (def_acl) {
03935                                         SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
03936                                 }
03937                                 data_size = (num_file_acls + num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE + SMB_POSIX_ACL_HEADER_SIZE;
03938                                 break;
03939                         }
03940 #endif
03941 
03942 
03943                 case SMB_QUERY_POSIX_LOCK:
03944                 {
03945                         NTSTATUS status = NT_STATUS_INVALID_LEVEL;
03946                         SMB_BIG_UINT count;
03947                         SMB_BIG_UINT offset;
03948                         uint32 lock_pid;
03949                         enum brl_type lock_type;
03950 
03951                         if (total_data != POSIX_LOCK_DATA_SIZE) {
03952                                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03953                         }
03954 
03955                         switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
03956                                 case POSIX_LOCK_TYPE_READ:
03957                                         lock_type = READ_LOCK;
03958                                         break;
03959                                 case POSIX_LOCK_TYPE_WRITE:
03960                                         lock_type = WRITE_LOCK;
03961                                         break;
03962                                 case POSIX_LOCK_TYPE_UNLOCK:
03963                                 default:
03964                                         /* There's no point in asking for an unlock... */
03965                                         talloc_destroy(data_ctx);
03966                                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
03967                         }
03968 
03969                         lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
03970 #if defined(HAVE_LONGLONG)
03971                         offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
03972                                         ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
03973                         count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
03974                                         ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
03975 #else /* HAVE_LONGLONG */
03976                         offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
03977                         count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
03978 #endif /* HAVE_LONGLONG */
03979 
03980                         status = query_lock(fsp,
03981                                         &lock_pid,
03982                                         &count,
03983                                         &offset,
03984                                         &lock_type,
03985                                         POSIX_LOCK);
03986 
03987                         if (ERROR_WAS_LOCK_DENIED(status)) {
03988                                 /* Here we need to report who has it locked... */
03989                                 data_size = POSIX_LOCK_DATA_SIZE;
03990 
03991                                 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, lock_type);
03992                                 SSVAL(pdata, POSIX_LOCK_FLAGS_OFFSET, 0);
03993                                 SIVAL(pdata, POSIX_LOCK_PID_OFFSET, lock_pid);
03994 #if defined(HAVE_LONGLONG)
03995                                 SIVAL(pdata, POSIX_LOCK_START_OFFSET, (uint32)(offset & 0xFFFFFFFF));
03996                                 SIVAL(pdata, POSIX_LOCK_START_OFFSET + 4, (uint32)((offset >> 32) & 0xFFFFFFFF));
03997                                 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, (uint32)(count & 0xFFFFFFFF));
03998                                 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET + 4, (uint32)((count >> 32) & 0xFFFFFFFF));
03999 #else /* HAVE_LONGLONG */
04000                                 SIVAL(pdata, POSIX_LOCK_START_OFFSET, offset);
04001                                 SIVAL(pdata, POSIX_LOCK_LEN_OFFSET, count);
04002 #endif /* HAVE_LONGLONG */
04003 
04004                         } else if (NT_STATUS_IS_OK(status)) {
04005                                 /* For success we just return a copy of what we sent
04006                                    with the lock type set to POSIX_LOCK_TYPE_UNLOCK. */
04007                                 data_size = POSIX_LOCK_DATA_SIZE;
04008                                 memcpy(pdata, lock_data, POSIX_LOCK_DATA_SIZE);
04009                                 SSVAL(pdata, POSIX_LOCK_TYPE_OFFSET, POSIX_LOCK_TYPE_UNLOCK);
04010                         } else {
04011                                 return ERROR_NT(status);
04012                         }
04013                         break;
04014                 }
04015 
04016                 default:
04017                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
04018         }
04019 
04020         send_trans2_replies(outbuf, bufsize, params, param_size, *ppdata, data_size, max_data_bytes);
04021 
04022         return(-1);
04023 }
04024 
04025 /****************************************************************************
04026  Set a hard link (called by UNIX extensions and by NT rename with HARD link
04027  code.
04028 ****************************************************************************/
04029 
04030 NTSTATUS hardlink_internals(connection_struct *conn, pstring oldname, pstring newname)
04031 {
04032         SMB_STRUCT_STAT sbuf1, sbuf2;
04033         pstring last_component_oldname;
04034         pstring last_component_newname;
04035         NTSTATUS status = NT_STATUS_OK;
04036 
04037         ZERO_STRUCT(sbuf1);
04038         ZERO_STRUCT(sbuf2);
04039 
04040         status = unix_convert(conn, oldname, False, last_component_oldname, &sbuf1);
04041         if (!NT_STATUS_IS_OK(status)) {
04042                 return status;
04043         }
04044 
04045         status = check_name(conn, oldname);
04046         if (!NT_STATUS_IS_OK(status)) {
04047                 return status;
04048         }
04049 
04050         /* source must already exist. */
04051         if (!VALID_STAT(sbuf1)) {
04052                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04053         }
04054 
04055         status = unix_convert(conn, newname, False, last_component_newname, &sbuf2);
04056         if (!NT_STATUS_IS_OK(status)) {
04057                 return status;
04058         }
04059 
04060         status = check_name(conn, newname);
04061         if (!NT_STATUS_IS_OK(status)) {
04062                 return status;
04063         }
04064 
04065         /* Disallow if newname already exists. */
04066         if (VALID_STAT(sbuf2)) {
04067                 return NT_STATUS_OBJECT_NAME_COLLISION;
04068         }
04069 
04070         /* No links from a directory. */
04071         if (S_ISDIR(sbuf1.st_mode)) {
04072                 return NT_STATUS_FILE_IS_A_DIRECTORY;
04073         }
04074 
04075         /* Ensure this is within the share. */
04076         status = reduce_name(conn, oldname);
04077         if (!NT_STATUS_IS_OK(status)) {
04078                 return status;
04079         }
04080 
04081         DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", newname, oldname ));
04082 
04083         if (SMB_VFS_LINK(conn,oldname,newname) != 0) {
04084                 status = map_nt_error_from_unix(errno);
04085                 DEBUG(3,("hardlink_internals: Error %s hard link %s -> %s\n",
04086                                 nt_errstr(status), newname, oldname));
04087         }
04088 
04089         return status;
04090 }
04091 
04092 /****************************************************************************
04093  Deal with setting the time from any of the setfilepathinfo functions.
04094 ****************************************************************************/
04095 
04096 static NTSTATUS smb_set_file_time(connection_struct *conn,
04097                                 files_struct *fsp,
04098                                 const char *fname,
04099                                 const SMB_STRUCT_STAT *psbuf,
04100                                 struct timespec ts[2])
04101 {
04102         uint32 action =
04103                 FILE_NOTIFY_CHANGE_LAST_ACCESS
04104                 |FILE_NOTIFY_CHANGE_LAST_WRITE;
04105 
04106         
04107         if (!VALID_STAT(*psbuf)) {
04108                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04109         }
04110 
04111         /* get some defaults (no modifications) if any info is zero or -1. */
04112         if (null_timespec(ts[0])) {
04113                 ts[0] = get_atimespec(psbuf);
04114                 action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
04115         }
04116 
04117         if (null_timespec(ts[1])) {
04118                 ts[1] = get_mtimespec(psbuf);
04119                 action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
04120         }
04121 
04122         DEBUG(6,("smb_set_file_time: actime: %s " , time_to_asc(convert_timespec_to_time_t(ts[0])) ));
04123         DEBUG(6,("smb_set_file_time: modtime: %s ", time_to_asc(convert_timespec_to_time_t(ts[1])) ));
04124 
04125         /*
04126          * Try and set the times of this file if
04127          * they are different from the current values.
04128          */
04129 
04130         {
04131                 struct timespec mts = get_mtimespec(psbuf);
04132                 struct timespec ats = get_atimespec(psbuf);
04133                 if ((timespec_compare(&ts[0], &ats) == 0) && (timespec_compare(&ts[1], &mts) == 0)) {
04134                         return NT_STATUS_OK;
04135                 }
04136         }
04137 
04138         if(fsp != NULL) {
04139                 /*
04140                  * This was a setfileinfo on an open file.
04141                  * NT does this a lot. We also need to 
04142                  * set the time here, as it can be read by 
04143                  * FindFirst/FindNext and with the patch for bug #2045
04144                  * in smbd/fileio.c it ensures that this timestamp is
04145                  * kept sticky even after a write. We save the request
04146                  * away and will set it on file close and after a write. JRA.
04147                  */
04148 
04149                 if (!null_timespec(ts[1])) {
04150                         DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
04151                                 time_to_asc(convert_timespec_to_time_t(ts[1])) ));
04152                         fsp_set_pending_modtime(fsp, ts[1]);
04153                 }
04154 
04155         }
04156         DEBUG(10,("smb_set_file_time: setting utimes to modified values.\n"));
04157 
04158         if(file_ntimes(conn, fname, ts)!=0) {
04159                 return map_nt_error_from_unix(errno);
04160         }
04161         if (action != 0) {
04162                 notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname);
04163         }
04164         return NT_STATUS_OK;
04165 }
04166 
04167 /****************************************************************************
04168  Deal with setting the dosmode from any of the setfilepathinfo functions.
04169 ****************************************************************************/
04170 
04171 static NTSTATUS smb_set_file_dosmode(connection_struct *conn,
04172                                 const char *fname,
04173                                 SMB_STRUCT_STAT *psbuf,
04174                                 uint32 dosmode)
04175 {
04176         if (!VALID_STAT(*psbuf)) {
04177                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04178         }
04179 
04180         if (dosmode) {
04181                 if (S_ISDIR(psbuf->st_mode)) {
04182                         dosmode |= aDIR;
04183                 } else {
04184                         dosmode &= ~aDIR;
04185                 }
04186         }
04187 
04188         DEBUG(6,("smb_set_file_dosmode: dosmode: 0x%x\n", (unsigned int)dosmode));
04189 
04190         /* check the mode isn't different, before changing it */
04191         if ((dosmode != 0) && (dosmode != dos_mode(conn, fname, psbuf))) {
04192 
04193                 DEBUG(10,("smb_set_file_dosmode: file %s : setting dos mode 0x%x\n",
04194                                         fname, (unsigned int)dosmode ));
04195 
04196                 if(file_set_dosmode(conn, fname, dosmode, psbuf, False)) {
04197                         DEBUG(2,("smb_set_file_dosmode: file_set_dosmode of %s failed (%s)\n",
04198                                                 fname, strerror(errno)));
04199                         return map_nt_error_from_unix(errno);
04200                 }
04201         }
04202         return NT_STATUS_OK;
04203 }
04204 
04205 /****************************************************************************
04206  Deal with setting the size from any of the setfilepathinfo functions.
04207 ****************************************************************************/
04208 
04209 static NTSTATUS smb_set_file_size(connection_struct *conn,
04210                                 files_struct *fsp,
04211                                 const char *fname,
04212                                 SMB_STRUCT_STAT *psbuf,
04213                                 SMB_OFF_T size)
04214 {
04215         NTSTATUS status = NT_STATUS_OK;
04216         files_struct *new_fsp = NULL;
04217 
04218         if (!VALID_STAT(*psbuf)) {
04219                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04220         }
04221 
04222         DEBUG(6,("smb_set_file_size: size: %.0f ", (double)size));
04223 
04224         if (size == get_file_size(*psbuf)) {
04225                 return NT_STATUS_OK;
04226         }
04227 
04228         DEBUG(10,("smb_set_file_size: file %s : setting new size to %.0f\n",
04229                 fname, (double)size ));
04230 
04231         if (fsp && fsp->fh->fd != -1) {
04232                 /* Handle based call. */
04233                 if (vfs_set_filelen(fsp, size) == -1) {
04234                         return map_nt_error_from_unix(errno);
04235                 }
04236                 return NT_STATUS_OK;
04237         }
04238 
04239         status = open_file_ntcreate(conn, fname, psbuf,
04240                                 FILE_WRITE_DATA,
04241                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
04242                                 FILE_OPEN,
04243                                 0,
04244                                 FILE_ATTRIBUTE_NORMAL,
04245                                 FORCE_OPLOCK_BREAK_TO_NONE,
04246                                 NULL, &new_fsp);
04247         
04248         if (!NT_STATUS_IS_OK(status)) {
04249                 /* NB. We check for open_was_deferred in the caller. */
04250                 return status;
04251         }
04252 
04253         if (vfs_set_filelen(new_fsp, size) == -1) {
04254                 status = map_nt_error_from_unix(errno);
04255                 close_file(new_fsp,NORMAL_CLOSE);
04256                 return status;
04257         }
04258 
04259         close_file(new_fsp,NORMAL_CLOSE);
04260         return NT_STATUS_OK;
04261 }
04262 
04263 /****************************************************************************
04264  Deal with SMB_INFO_SET_EA.
04265 ****************************************************************************/
04266 
04267 static NTSTATUS smb_info_set_ea(connection_struct *conn,
04268                                 const char *pdata,
04269                                 int total_data,
04270                                 files_struct *fsp,
04271                                 const char *fname)
04272 {
04273         struct ea_list *ea_list = NULL;
04274         TALLOC_CTX *ctx = NULL;
04275         NTSTATUS status = NT_STATUS_OK;
04276 
04277         if (total_data < 10) {
04278 
04279                 /* OS/2 workplace shell seems to send SET_EA requests of "null"
04280                    length. They seem to have no effect. Bug #3212. JRA */
04281 
04282                 if ((total_data == 4) && (IVAL(pdata,0) == 4)) {
04283                         /* We're done. We only get EA info in this call. */
04284                         return NT_STATUS_OK;
04285                 }
04286 
04287                 return NT_STATUS_INVALID_PARAMETER;
04288         }
04289 
04290         if (IVAL(pdata,0) > total_data) {
04291                 DEBUG(10,("smb_info_set_ea: bad total data size (%u) > %u\n",
04292                         IVAL(pdata,0), (unsigned int)total_data));
04293                 return NT_STATUS_INVALID_PARAMETER;
04294         }
04295 
04296         ctx = talloc_init("SMB_INFO_SET_EA");
04297         if (!ctx) {
04298                 return NT_STATUS_NO_MEMORY;
04299         }
04300         ea_list = read_ea_list(ctx, pdata + 4, total_data - 4);
04301         if (!ea_list) {
04302                 talloc_destroy(ctx);
04303                 return NT_STATUS_INVALID_PARAMETER;
04304         }
04305         status = set_ea(conn, fsp, fname, ea_list);
04306         talloc_destroy(ctx);
04307 
04308         return status;
04309 }
04310 
04311 /****************************************************************************
04312  Deal with SMB_SET_FILE_DISPOSITION_INFO.
04313 ****************************************************************************/
04314 
04315 static NTSTATUS smb_set_file_disposition_info(connection_struct *conn,
04316                                 const char *pdata,
04317                                 int total_data,
04318                                 files_struct *fsp,
04319                                 const char *fname,
04320                                 SMB_STRUCT_STAT *psbuf)
04321 {
04322         NTSTATUS status = NT_STATUS_OK;
04323         BOOL delete_on_close;
04324         uint32 dosmode = 0;
04325 
04326         if (total_data < 1) {
04327                 return NT_STATUS_INVALID_PARAMETER;
04328         }
04329 
04330         if (fsp == NULL) {
04331                 return NT_STATUS_INVALID_HANDLE;
04332         }
04333 
04334         delete_on_close = (CVAL(pdata,0) ? True : False);
04335         dosmode = dos_mode(conn, fname, psbuf);
04336 
04337         DEBUG(10,("smb_set_file_disposition_info: file %s, dosmode = %u, "
04338                 "delete_on_close = %u\n",
04339                 fsp->fsp_name,
04340                 (unsigned int)dosmode,
04341                 (unsigned int)delete_on_close ));
04342 
04343         status = can_set_delete_on_close(fsp, delete_on_close, dosmode);
04344  
04345         if (!NT_STATUS_IS_OK(status)) {
04346                 return status;
04347         }
04348 
04349         /* The set is across all open files on this dev/inode pair. */
04350         if (!set_delete_on_close(fsp, delete_on_close, &current_user.ut)) {
04351                 return NT_STATUS_ACCESS_DENIED;
04352         }
04353         return NT_STATUS_OK;
04354 }
04355 
04356 /****************************************************************************
04357  Deal with SMB_FILE_POSITION_INFORMATION.
04358 ****************************************************************************/
04359 
04360 static NTSTATUS smb_file_position_information(connection_struct *conn,
04361                                 const char *pdata,
04362                                 int total_data,
04363                                 files_struct *fsp)
04364 {
04365         SMB_BIG_UINT position_information;
04366 
04367         if (total_data < 8) {
04368                 return NT_STATUS_INVALID_PARAMETER;
04369         }
04370 
04371         if (fsp == NULL) {
04372                 /* Ignore on pathname based set. */
04373                 return NT_STATUS_OK;
04374         }
04375 
04376         position_information = (SMB_BIG_UINT)IVAL(pdata,0);
04377 #ifdef LARGE_SMB_OFF_T
04378         position_information |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
04379 #else /* LARGE_SMB_OFF_T */
04380         if (IVAL(pdata,4) != 0) {
04381                 /* more than 32 bits? */
04382                 return NT_STATUS_INVALID_PARAMETER;
04383         }
04384 #endif /* LARGE_SMB_OFF_T */
04385 
04386         DEBUG(10,("smb_file_position_information: Set file position information for file %s to %.0f\n",
04387                 fsp->fsp_name, (double)position_information ));
04388         fsp->fh->position_information = position_information;
04389         return NT_STATUS_OK;
04390 }
04391 
04392 /****************************************************************************
04393  Deal with SMB_FILE_MODE_INFORMATION.
04394 ****************************************************************************/
04395 
04396 static NTSTATUS smb_file_mode_information(connection_struct *conn,
04397                                 const char *pdata,
04398                                 int total_data)
04399 {
04400         uint32 mode;
04401 
04402         if (total_data < 4) {
04403                 return NT_STATUS_INVALID_PARAMETER;
04404         }
04405         mode = IVAL(pdata,0);
04406         if (mode != 0 && mode != 2 && mode != 4 && mode != 6) {
04407                 return NT_STATUS_INVALID_PARAMETER;
04408         }
04409         return NT_STATUS_OK;
04410 }
04411 
04412 /****************************************************************************
04413  Deal with SMB_SET_FILE_UNIX_LINK (create a UNIX symlink).
04414 ****************************************************************************/
04415 
04416 static NTSTATUS smb_set_file_unix_link(connection_struct *conn,
04417                                 char *inbuf,
04418                                 const char *pdata,
04419                                 int total_data,
04420                                 const char *fname)
04421 {
04422         pstring link_target;
04423         const char *newname = fname;
04424         NTSTATUS status = NT_STATUS_OK;
04425 
04426         /* Set a symbolic link. */
04427         /* Don't allow this if follow links is false. */
04428 
04429         if (total_data == 0) {
04430                 return NT_STATUS_INVALID_PARAMETER;
04431         }
04432 
04433         if (!lp_symlinks(SNUM(conn))) {
04434                 return NT_STATUS_ACCESS_DENIED;
04435         }
04436 
04437         srvstr_pull(inbuf, link_target, pdata, sizeof(link_target), total_data, STR_TERMINATE);
04438 
04439         /* !widelinks forces the target path to be within the share. */
04440         /* This means we can interpret the target as a pathname. */
04441         if (!lp_widelinks(SNUM(conn))) {
04442                 pstring rel_name;
04443                 char *last_dirp = NULL;
04444 
04445                 if (*link_target == '/') {
04446                         /* No absolute paths allowed. */
04447                         return NT_STATUS_ACCESS_DENIED;
04448                 }
04449                 pstrcpy(rel_name, newname);
04450                 last_dirp = strrchr_m(rel_name, '/');
04451                 if (last_dirp) {
04452                         last_dirp[1] = '\0';
04453                 } else {
04454                         pstrcpy(rel_name, "./");
04455                 }
04456                 pstrcat(rel_name, link_target);
04457 
04458                 status = check_name(conn, rel_name);
04459                 if (!NT_STATUS_IS_OK(status)) {
04460                         return status;
04461                 }
04462         }
04463 
04464         DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n",
04465                         newname, link_target ));
04466 
04467         if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) {
04468                 return map_nt_error_from_unix(errno);
04469         }
04470 
04471         return NT_STATUS_OK;
04472 }
04473 
04474 /****************************************************************************
04475  Deal with SMB_SET_FILE_UNIX_HLINK (create a UNIX hard link).
04476 ****************************************************************************/
04477 
04478 static NTSTATUS smb_set_file_unix_hlink(connection_struct *conn,
04479                                 char *inbuf,
04480                                 char *outbuf,
04481                                 const char *pdata,
04482                                 int total_data,
04483                                 pstring fname)
04484 {
04485         pstring oldname;
04486         NTSTATUS status = NT_STATUS_OK;
04487 
04488         /* Set a hard link. */
04489         if (total_data == 0) {
04490                 return NT_STATUS_INVALID_PARAMETER;
04491         }
04492 
04493         srvstr_get_path(inbuf, oldname, pdata, sizeof(oldname), total_data, STR_TERMINATE, &status);
04494         if (!NT_STATUS_IS_OK(status)) {
04495                 return status;
04496         }
04497 
04498         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, oldname);
04499         if (!NT_STATUS_IS_OK(status)) {
04500                 return status;
04501         }
04502 
04503         DEBUG(10,("smb_set_file_unix_hlink: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
04504                 fname, oldname));
04505 
04506         return hardlink_internals(conn, oldname, fname);
04507 }
04508 
04509 /****************************************************************************
04510  Deal with SMB_FILE_RENAME_INFORMATION.
04511 ****************************************************************************/
04512 
04513 static NTSTATUS smb_file_rename_information(connection_struct *conn,
04514                                 char *inbuf,
04515                                 char *outbuf,
04516                                 const char *pdata,
04517                                 int total_data,
04518                                 files_struct *fsp,
04519                                 pstring fname)
04520 {
04521         BOOL overwrite;
04522         /* uint32 root_fid; */  /* Not used */
04523         uint32 len;
04524         pstring newname;
04525         pstring base_name;
04526         BOOL dest_has_wcard = False;
04527         NTSTATUS status = NT_STATUS_OK;
04528         char *p;
04529 
04530         if (total_data < 13) {
04531                 return NT_STATUS_INVALID_PARAMETER;
04532         }
04533 
04534         overwrite = (CVAL(pdata,0) ? True : False);
04535         /* root_fid = IVAL(pdata,4); */
04536         len = IVAL(pdata,8);
04537 
04538         if (len > (total_data - 12) || (len == 0)) {
04539                 return NT_STATUS_INVALID_PARAMETER;
04540         }
04541 
04542         srvstr_get_path_wcard(inbuf, newname, &pdata[12], sizeof(newname), len, 0, &status, &dest_has_wcard);
04543         if (!NT_STATUS_IS_OK(status)) {
04544                 return status;
04545         }
04546 
04547         status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard);
04548         if (!NT_STATUS_IS_OK(status)) {
04549                 return status;
04550         }
04551 
04552         /* Check the new name has no '/' characters. */
04553         if (strchr_m(newname, '/')) {
04554                 return NT_STATUS_NOT_SUPPORTED;
04555         }
04556 
04557         /* Create the base directory. */
04558         pstrcpy(base_name, fname);
04559         p = strrchr_m(base_name, '/');
04560         if (p) {
04561                 p[1] = '\0';
04562         } else {
04563                 pstrcpy(base_name, "./");
04564         }
04565         /* Append the new name. */
04566         pstrcat(base_name, newname);
04567 
04568         if (fsp) {
04569                 DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION (fnum %d) %s -> %s\n",
04570                         fsp->fnum, fsp->fsp_name, base_name ));
04571                 status = rename_internals_fsp(conn, fsp, base_name, 0, overwrite);
04572         } else {
04573                 DEBUG(10,("smb_file_rename_information: SMB_FILE_RENAME_INFORMATION %s -> %s\n",
04574                         fname, newname ));
04575                 status = rename_internals(conn, fname, base_name, 0, overwrite, False, dest_has_wcard);
04576         }
04577 
04578         return status;
04579 }
04580 
04581 /****************************************************************************
04582  Deal with SMB_SET_POSIX_ACL.
04583 ****************************************************************************/
04584 
04585 #if defined(HAVE_POSIX_ACLS)
04586 static NTSTATUS smb_set_posix_acl(connection_struct *conn,
04587                                 const char *pdata,
04588                                 int total_data,
04589                                 files_struct *fsp,
04590                                 const char *fname,
04591                                 SMB_STRUCT_STAT *psbuf)
04592 {
04593         uint16 posix_acl_version;
04594         uint16 num_file_acls;
04595         uint16 num_def_acls;
04596         BOOL valid_file_acls = True;
04597         BOOL valid_def_acls = True;
04598 
04599         if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
04600                 return NT_STATUS_INVALID_PARAMETER;
04601         }
04602         posix_acl_version = SVAL(pdata,0);
04603         num_file_acls = SVAL(pdata,2);
04604         num_def_acls = SVAL(pdata,4);
04605 
04606         if (num_file_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
04607                 valid_file_acls = False;
04608                 num_file_acls = 0;
04609         }
04610 
04611         if (num_def_acls == SMB_POSIX_IGNORE_ACE_ENTRIES) {
04612                 valid_def_acls = False;
04613                 num_def_acls = 0;
04614         }
04615 
04616         if (posix_acl_version != SMB_POSIX_ACL_VERSION) {
04617                 return NT_STATUS_INVALID_PARAMETER;
04618         }
04619 
04620         if (total_data < SMB_POSIX_ACL_HEADER_SIZE +
04621                         (num_file_acls+num_def_acls)*SMB_POSIX_ACL_ENTRY_SIZE) {
04622                 return NT_STATUS_INVALID_PARAMETER;
04623         }
04624 
04625         DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
04626                 fname ? fname : fsp->fsp_name,
04627                 (unsigned int)num_file_acls,
04628                 (unsigned int)num_def_acls));
04629 
04630         if (valid_file_acls && !set_unix_posix_acl(conn, fsp, fname, num_file_acls,
04631                         pdata + SMB_POSIX_ACL_HEADER_SIZE)) {
04632                 return map_nt_error_from_unix(errno);
04633         }
04634 
04635         if (valid_def_acls && !set_unix_posix_default_acl(conn, fname, psbuf, num_def_acls,
04636                         pdata + SMB_POSIX_ACL_HEADER_SIZE +
04637                         (num_file_acls*SMB_POSIX_ACL_ENTRY_SIZE))) {
04638                 return map_nt_error_from_unix(errno);
04639         }
04640         return NT_STATUS_OK;
04641 }
04642 #endif
04643 
04644 /****************************************************************************
04645  Deal with SMB_SET_POSIX_LOCK.
04646 ****************************************************************************/
04647 
04648 static NTSTATUS smb_set_posix_lock(connection_struct *conn,
04649                                 char *inbuf,
04650                                 int length,
04651                                 const char *pdata,
04652                                 int total_data,
04653                                 files_struct *fsp)
04654 {
04655         SMB_BIG_UINT count;
04656         SMB_BIG_UINT offset;
04657         uint32 lock_pid;
04658         BOOL blocking_lock = False;
04659         enum brl_type lock_type;
04660         NTSTATUS status = NT_STATUS_OK;
04661 
04662         if (fsp == NULL || fsp->fh->fd == -1) {
04663                 return NT_STATUS_INVALID_HANDLE;
04664         }
04665 
04666         if (total_data != POSIX_LOCK_DATA_SIZE) {
04667                 return NT_STATUS_INVALID_PARAMETER;
04668         }
04669 
04670         switch (SVAL(pdata, POSIX_LOCK_TYPE_OFFSET)) {
04671                 case POSIX_LOCK_TYPE_READ:
04672                         lock_type = READ_LOCK;
04673                         break;
04674                 case POSIX_LOCK_TYPE_WRITE:
04675                         /* Return the right POSIX-mappable error code for files opened read-only. */
04676                         if (!fsp->can_write) {
04677                                 return NT_STATUS_INVALID_HANDLE;
04678                         }
04679                         lock_type = WRITE_LOCK;
04680                         break;
04681                 case POSIX_LOCK_TYPE_UNLOCK:
04682                         lock_type = UNLOCK_LOCK;
04683                         break;
04684                 default:
04685                         return NT_STATUS_INVALID_PARAMETER;
04686         }
04687 
04688         if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_NOWAIT) {
04689                 blocking_lock = False;
04690         } else if (SVAL(pdata,POSIX_LOCK_FLAGS_OFFSET) == POSIX_LOCK_FLAG_WAIT) {
04691                 blocking_lock = True;
04692         } else {
04693                 return NT_STATUS_INVALID_PARAMETER;
04694         }
04695 
04696         if (!lp_blocking_locks(SNUM(conn))) { 
04697                 blocking_lock = False;
04698         }
04699 
04700         lock_pid = IVAL(pdata, POSIX_LOCK_PID_OFFSET);
04701 #if defined(HAVE_LONGLONG)
04702         offset = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_START_OFFSET+4))) << 32) |
04703                         ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_START_OFFSET));
04704         count = (((SMB_BIG_UINT) IVAL(pdata,(POSIX_LOCK_LEN_OFFSET+4))) << 32) |
04705                         ((SMB_BIG_UINT) IVAL(pdata,POSIX_LOCK_LEN_OFFSET));
04706 #else /* HAVE_LONGLONG */
04707         offset = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_START_OFFSET);
04708         count = (SMB_BIG_UINT)IVAL(pdata,POSIX_LOCK_LEN_OFFSET);
04709 #endif /* HAVE_LONGLONG */
04710 
04711         DEBUG(10,("smb_set_posix_lock: file %s, lock_type = %u,"
04712                         "lock_pid = %u, count = %.0f, offset = %.0f\n",
04713                 fsp->fsp_name,
04714                 (unsigned int)lock_type,
04715                 (unsigned int)lock_pid,
04716                 (double)count,
04717                 (double)offset ));
04718 
04719         if (lock_type == UNLOCK_LOCK) {
04720                 status = do_unlock(fsp,
04721                                 lock_pid,
04722                                 count,
04723                                 offset,
04724                                 POSIX_LOCK);
04725         } else {
04726                 uint32 block_smbpid;
04727 
04728                 struct byte_range_lock *br_lck = do_lock(fsp,
04729                                                         lock_pid,
04730                                                         count,
04731                                                         offset,
04732                                                         lock_type,
04733                                                         POSIX_LOCK,
04734                                                         blocking_lock,
04735                                                         &status,
04736                                                         &block_smbpid);
04737 
04738                 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
04739                         /*
04740                          * A blocking lock was requested. Package up
04741                          * this smb into a queued request and push it
04742                          * onto the blocking lock queue.
04743                          */
04744                         if(push_blocking_lock_request(br_lck,
04745                                                 inbuf, length,
04746                                                 fsp,
04747                                                 -1, /* infinite timeout. */
04748                                                 0,
04749                                                 lock_pid,
04750                                                 lock_type,
04751                                                 POSIX_LOCK,
04752                                                 offset,
04753                                                 count,
04754                                                 block_smbpid)) {
04755                                 TALLOC_FREE(br_lck);
04756                                 return status;
04757                         }
04758                 }
04759                 TALLOC_FREE(br_lck);
04760         }
04761 
04762         return status;
04763 }
04764 
04765 /****************************************************************************
04766  Deal with SMB_INFO_STANDARD.
04767 ****************************************************************************/
04768 
04769 static NTSTATUS smb_set_info_standard(connection_struct *conn,
04770                                         const char *pdata,
04771                                         int total_data,
04772                                         files_struct *fsp,
04773                                         const char *fname,
04774                                         const SMB_STRUCT_STAT *psbuf)
04775 {
04776         struct timespec ts[2];
04777 
04778         if (total_data < 12) {
04779                 return NT_STATUS_INVALID_PARAMETER;
04780         }
04781 
04782         /* access time */
04783         ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastAccess));
04784         /* write time */
04785         ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastWrite));
04786 
04787         DEBUG(10,("smb_set_info_standard: file %s\n",
04788                 fname ? fname : fsp->fsp_name ));
04789 
04790         return smb_set_file_time(conn,
04791                                 fsp,
04792                                 fname,
04793                                 psbuf,
04794                                 ts);
04795 }
04796 
04797 /****************************************************************************
04798  Deal with SMB_SET_FILE_BASIC_INFO.
04799 ****************************************************************************/
04800 
04801 static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
04802                                         const char *pdata,
04803                                         int total_data,
04804                                         files_struct *fsp,
04805                                         const char *fname,
04806                                         SMB_STRUCT_STAT *psbuf)
04807 {
04808         /* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
04809         struct timespec write_time;
04810         struct timespec changed_time;
04811         uint32 dosmode = 0;
04812         struct timespec ts[2];
04813         NTSTATUS status = NT_STATUS_OK;
04814 
04815         if (total_data < 36) {
04816                 return NT_STATUS_INVALID_PARAMETER;
04817         }
04818 
04819         /* Set the attributes */
04820         dosmode = IVAL(pdata,32);
04821         status = smb_set_file_dosmode(conn,
04822                                         fname,
04823                                         psbuf,
04824                                         dosmode);
04825         if (!NT_STATUS_IS_OK(status)) {
04826                 return status;
04827         }
04828 
04829         /* Ignore create time at offset pdata. */
04830 
04831         /* access time */
04832         ts[0] = interpret_long_date(pdata+8);
04833 
04834         write_time = interpret_long_date(pdata+16);
04835         changed_time = interpret_long_date(pdata+24);
04836 
04837         /* mtime */
04838         ts[1] = timespec_min(&write_time, &changed_time);
04839 
04840         if ((timespec_compare(&write_time, &ts[1]) == 1) && !null_timespec(write_time)) {
04841                 ts[1] = write_time;
04842         }
04843 
04844         /* Prefer a defined time to an undefined one. */
04845         if (null_timespec(ts[1])) {
04846                 ts[1] = null_timespec(write_time) ? changed_time : write_time;
04847         }
04848 
04849         DEBUG(10,("smb_set_file_basic_info: file %s\n",
04850                 fname ? fname : fsp->fsp_name ));
04851 
04852         return smb_set_file_time(conn,
04853                                 fsp,
04854                                 fname,
04855                                 psbuf,
04856                                 ts);
04857 }
04858 
04859 /****************************************************************************
04860  Deal with SMB_SET_FILE_ALLOCATION_INFO.
04861 ****************************************************************************/
04862 
04863 static NTSTATUS smb_set_file_allocation_info(connection_struct *conn,
04864                                         const char *pdata,
04865                                         int total_data,
04866                                         files_struct *fsp,
04867                                         const char *fname,
04868                                         SMB_STRUCT_STAT *psbuf)
04869 {
04870         SMB_BIG_UINT allocation_size = 0;
04871         NTSTATUS status = NT_STATUS_OK;
04872         files_struct *new_fsp = NULL;
04873 
04874         if (!VALID_STAT(*psbuf)) {
04875                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04876         }
04877 
04878         if (total_data < 8) {
04879                 return NT_STATUS_INVALID_PARAMETER;
04880         }
04881 
04882         allocation_size = (SMB_BIG_UINT)IVAL(pdata,0);
04883 #ifdef LARGE_SMB_OFF_T
04884         allocation_size |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32);
04885 #else /* LARGE_SMB_OFF_T */
04886         if (IVAL(pdata,4) != 0) {
04887                 /* more than 32 bits? */
04888                 return NT_STATUS_INVALID_PARAMETER;
04889         }
04890 #endif /* LARGE_SMB_OFF_T */
04891 
04892         DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for file %s to %.0f\n",
04893                         fname, (double)allocation_size ));
04894 
04895         if (allocation_size) {
04896                 allocation_size = smb_roundup(conn, allocation_size);
04897         }
04898 
04899         DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n",
04900                         fname, (double)allocation_size ));
04901 
04902         if (fsp && fsp->fh->fd != -1) {
04903                 /* Open file handle. */
04904                 /* Only change if needed. */
04905                 if (allocation_size != get_file_size(*psbuf)) {
04906                         if (vfs_allocate_file_space(fsp, allocation_size) == -1) {
04907                                 return map_nt_error_from_unix(errno);
04908                         }
04909                 }
04910                 /* But always update the time. */
04911                 if (null_timespec(fsp->pending_modtime)) {
04912                         /*
04913                          * This is equivalent to a write. Ensure it's seen immediately
04914                          * if there are no pending writes.
04915                          */
04916                         set_filetime(fsp->conn, fsp->fsp_name, timespec_current());
04917                 }
04918                 return NT_STATUS_OK;
04919         }
04920 
04921         /* Pathname or stat or directory file. */
04922 
04923         status = open_file_ntcreate(conn, fname, psbuf,
04924                                 FILE_WRITE_DATA,
04925                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
04926                                 FILE_OPEN,
04927                                 0,
04928                                 FILE_ATTRIBUTE_NORMAL,
04929                                 FORCE_OPLOCK_BREAK_TO_NONE,
04930                                 NULL, &new_fsp);
04931 
04932         if (!NT_STATUS_IS_OK(status)) {
04933                 /* NB. We check for open_was_deferred in the caller. */
04934                 return status;
04935         }
04936 
04937         /* Only change if needed. */
04938         if (allocation_size != get_file_size(*psbuf)) {
04939                 if (vfs_allocate_file_space(new_fsp, allocation_size) == -1) {
04940                         status = map_nt_error_from_unix(errno);
04941                         close_file(new_fsp,NORMAL_CLOSE);
04942                         return status;
04943                 }
04944         }
04945 
04946         /* Changing the allocation size should set the last mod time. */
04947         /* Don't need to call set_filetime as this will be flushed on
04948          * close. */
04949 
04950         fsp_set_pending_modtime(new_fsp, timespec_current());
04951 
04952         close_file(new_fsp,NORMAL_CLOSE);
04953         return NT_STATUS_OK;
04954 }
04955 
04956 /****************************************************************************
04957  Deal with SMB_SET_FILE_END_OF_FILE_INFO.
04958 ****************************************************************************/
04959 
04960 static NTSTATUS smb_set_file_end_of_file_info(connection_struct *conn,
04961                                         const char *pdata,
04962                                         int total_data,
04963                                         files_struct *fsp,
04964                                         const char *fname,
04965                                         SMB_STRUCT_STAT *psbuf)
04966 {
04967         SMB_OFF_T size;
04968 
04969         if (total_data < 8) {
04970                 return NT_STATUS_INVALID_PARAMETER;
04971         }
04972 
04973         size = IVAL(pdata,0);
04974 #ifdef LARGE_SMB_OFF_T
04975         size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
04976 #else /* LARGE_SMB_OFF_T */
04977         if (IVAL(pdata,4) != 0) {
04978                 /* more than 32 bits? */
04979                 return NT_STATUS_INVALID_PARAMETER;
04980         }
04981 #endif /* LARGE_SMB_OFF_T */
04982         DEBUG(10,("smb_set_file_end_of_file_info: Set end of file info for "
04983                 "file %s to %.0f\n", fname, (double)size ));
04984 
04985         return smb_set_file_size(conn,
04986                                 fsp,
04987                                 fname,
04988                                 psbuf,
04989                                 size);
04990 }
04991 
04992 /****************************************************************************
04993  Allow a UNIX info mknod.
04994 ****************************************************************************/
04995 
04996 static NTSTATUS smb_unix_mknod(connection_struct *conn,
04997                                         const char *pdata,
04998                                         int total_data,
04999                                         const char *fname,
05000                                         SMB_STRUCT_STAT *psbuf)
05001 {
05002         uint32 file_type = IVAL(pdata,56);
05003 #if defined(HAVE_MAKEDEV)
05004         uint32 dev_major = IVAL(pdata,60);
05005         uint32 dev_minor = IVAL(pdata,68);
05006 #endif
05007         SMB_DEV_T dev = (SMB_DEV_T)0;
05008         uint32 raw_unixmode = IVAL(pdata,84);
05009         NTSTATUS status;
05010         mode_t unixmode;
05011 
05012         if (total_data < 100) {
05013                 return NT_STATUS_INVALID_PARAMETER;
05014         }
05015 
05016         status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_FILE, &unixmode);
05017         if (!NT_STATUS_IS_OK(status)) {
05018                 return status;
05019         }
05020 
05021 #if defined(HAVE_MAKEDEV)
05022         dev = makedev(dev_major, dev_minor);
05023 #endif
05024 
05025         switch (file_type) {
05026 #if defined(S_IFIFO)
05027                 case UNIX_TYPE_FIFO:
05028                         unixmode |= S_IFIFO;
05029                         break;
05030 #endif
05031 #if defined(S_IFSOCK)
05032                 case UNIX_TYPE_SOCKET:
05033                         unixmode |= S_IFSOCK;
05034                         break;
05035 #endif
05036 #if defined(S_IFCHR)
05037                 case UNIX_TYPE_CHARDEV:
05038                         unixmode |= S_IFCHR;
05039                         break;
05040 #endif
05041 #if defined(S_IFBLK)
05042                 case UNIX_TYPE_BLKDEV:
05043                         unixmode |= S_IFBLK;
05044                         break;
05045 #endif
05046                 default:
05047                         return NT_STATUS_INVALID_PARAMETER;
05048         }
05049 
05050         DEBUG(10,("smb_unix_mknod: SMB_SET_FILE_UNIX_BASIC doing mknod dev %.0f mode \
05051 0%o for file %s\n", (double)dev, (unsigned int)unixmode, fname ));
05052 
05053         /* Ok - do the mknod. */
05054         if (SMB_VFS_MKNOD(conn, fname, unixmode, dev) != 0) {
05055                 return map_nt_error_from_unix(errno);
05056         }
05057 
05058         /* If any of the other "set" calls fail we
05059          * don't want to end up with a half-constructed mknod.
05060          */
05061 
05062         if (lp_inherit_perms(SNUM(conn))) {
05063                 inherit_access_acl(
05064                         conn, parent_dirname(fname),
05065                         fname, unixmode);
05066         }
05067 
05068         if (SMB_VFS_STAT(conn, fname, psbuf) != 0) {
05069                 status = map_nt_error_from_unix(errno);
05070                 SMB_VFS_UNLINK(conn,fname);
05071                 return status;
05072         }
05073         return NT_STATUS_OK;
05074 }
05075 
05076 /****************************************************************************
05077  Deal with SMB_SET_FILE_UNIX_BASIC.
05078 ****************************************************************************/
05079 
05080 static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
05081                                         const char *pdata,
05082                                         int total_data,
05083                                         files_struct *fsp,
05084                                         const char *fname,
05085                                         SMB_STRUCT_STAT *psbuf)
05086 {
05087         struct timespec ts[2];
05088         uint32 raw_unixmode;
05089         mode_t unixmode;
05090         SMB_OFF_T size = 0;
05091         uid_t set_owner = (uid_t)SMB_UID_NO_CHANGE;
05092         gid_t set_grp = (uid_t)SMB_GID_NO_CHANGE;
05093         NTSTATUS status = NT_STATUS_OK;
05094         BOOL delete_on_fail = False;
05095         enum perm_type ptype;
05096 
05097         if (total_data < 100) {
05098                 return NT_STATUS_INVALID_PARAMETER;
05099         }
05100 
05101         if(IVAL(pdata, 0) != SMB_SIZE_NO_CHANGE_LO &&
05102            IVAL(pdata, 4) != SMB_SIZE_NO_CHANGE_HI) {
05103                 size=IVAL(pdata,0); /* first 8 Bytes are size */
05104 #ifdef LARGE_SMB_OFF_T
05105                 size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
05106 #else /* LARGE_SMB_OFF_T */
05107                 if (IVAL(pdata,4) != 0) {
05108                         /* more than 32 bits? */
05109                         return NT_STATUS_INVALID_PARAMETER;
05110                 }
05111 #endif /* LARGE_SMB_OFF_T */
05112         }
05113 
05114         ts[0] = interpret_long_date(pdata+24); /* access_time */
05115         ts[1] = interpret_long_date(pdata+32); /* modification_time */
05116         set_owner = (uid_t)IVAL(pdata,40);
05117         set_grp = (gid_t)IVAL(pdata,48);
05118         raw_unixmode = IVAL(pdata,84);
05119 
05120         if (VALID_STAT(*psbuf)) {
05121                 if (S_ISDIR(psbuf->st_mode)) {
05122                         ptype = PERM_EXISTING_DIR;
05123                 } else {
05124                         ptype = PERM_EXISTING_FILE;
05125                 }
05126         } else {
05127                 ptype = PERM_NEW_FILE;
05128         }
05129 
05130         status = unix_perms_from_wire(conn, psbuf, raw_unixmode, ptype, &unixmode);
05131         if (!NT_STATUS_IS_OK(status)) {
05132                 return status;
05133         }
05134 
05135         DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC: name = %s \
05136 size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
05137                 fname, (double)size, (unsigned int)set_owner, (unsigned int)set_grp, (int)raw_unixmode));
05138 
05139         if (!VALID_STAT(*psbuf)) {
05140                 /*
05141                  * The only valid use of this is to create character and block
05142                  * devices, and named pipes. This is deprecated (IMHO) and 
05143                  * a new info level should be used for mknod. JRA.
05144                  */
05145 
05146                 status = smb_unix_mknod(conn,
05147                                         pdata,
05148                                         total_data,
05149                                         fname,
05150                                         psbuf);
05151                 if (!NT_STATUS_IS_OK(status)) {
05152                         return status;
05153                 }
05154 
05155                 /* Ensure we don't try and change anything else. */
05156                 raw_unixmode = SMB_MODE_NO_CHANGE;
05157                 size = get_file_size(*psbuf);
05158                 ts[0] = get_atimespec(psbuf);
05159                 ts[1] = get_mtimespec(psbuf);
05160                 /* 
05161                  * We continue here as we might want to change the 
05162                  * owner uid/gid.
05163                  */
05164                 delete_on_fail = True;
05165         }
05166 
05167 #if 1
05168         /* Horrible backwards compatibility hack as an old server bug
05169          * allowed a CIFS client bug to remain unnoticed :-(. JRA.
05170          * */
05171 
05172         if (!size) {
05173                 size = get_file_size(*psbuf);
05174         }
05175 #endif
05176 
05177         /*
05178          * Deal with the UNIX specific mode set.
05179          */
05180 
05181         if (raw_unixmode != SMB_MODE_NO_CHANGE) {
05182                 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC setting mode 0%o for file %s\n",
05183                         (unsigned int)unixmode, fname ));
05184                 if (SMB_VFS_CHMOD(conn, fname, unixmode) != 0) {
05185                         return map_nt_error_from_unix(errno);
05186                 }
05187         }
05188 
05189         /*
05190          * Deal with the UNIX specific uid set.
05191          */
05192 
05193         if ((set_owner != (uid_t)SMB_UID_NO_CHANGE) && (psbuf->st_uid != set_owner)) {
05194                 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing owner %u for file %s\n",
05195                         (unsigned int)set_owner, fname ));
05196                 if (SMB_VFS_CHOWN(conn, fname, set_owner, (gid_t)-1) != 0) {
05197                         status = map_nt_error_from_unix(errno);
05198                         if (delete_on_fail) {
05199                                 SMB_VFS_UNLINK(conn,fname);
05200                         }
05201                         return status;
05202                 }
05203         }
05204 
05205         /*
05206          * Deal with the UNIX specific gid set.
05207          */
05208 
05209         if ((set_grp != (uid_t)SMB_GID_NO_CHANGE) && (psbuf->st_gid != set_grp)) {
05210                 DEBUG(10,("smb_set_file_unix_basic: SMB_SET_FILE_UNIX_BASIC changing group %u for file %s\n",
05211                         (unsigned int)set_owner, fname ));
05212                 if (SMB_VFS_CHOWN(conn, fname, (uid_t)-1, set_grp) != 0) {
05213                         status = map_nt_error_from_unix(errno);
05214                         if (delete_on_fail) {
05215                                 SMB_VFS_UNLINK(conn,fname);
05216                         }
05217                         return status;
05218                 }
05219         }
05220 
05221         /* Deal with any size changes. */
05222 
05223         status = smb_set_file_size(conn,
05224                                 fsp,
05225                                 fname,
05226                                 psbuf,
05227                                 size);
05228         if (!NT_STATUS_IS_OK(status)) {
05229                 return status;
05230         }
05231 
05232         /* Deal with any time changes. */
05233 
05234         return smb_set_file_time(conn,
05235                                 fsp,
05236                                 fname,
05237                                 psbuf,
05238                                 ts);
05239 }
05240 
05241 /****************************************************************************
05242  Deal with SMB_SET_FILE_UNIX_INFO2.
05243 ****************************************************************************/
05244 
05245 static NTSTATUS smb_set_file_unix_info2(connection_struct *conn,
05246                                         const char *pdata,
05247                                         int total_data,
05248                                         files_struct *fsp,
05249                                         const char *fname,
05250                                         SMB_STRUCT_STAT *psbuf)
05251 {
05252         NTSTATUS status;
05253         uint32 smb_fflags;
05254         uint32 smb_fmask;
05255 
05256         if (total_data < 116) {
05257                 return NT_STATUS_INVALID_PARAMETER;
05258         }
05259 
05260         /* Start by setting all the fields that are common between UNIX_BASIC
05261          * and UNIX_INFO2.
05262          */
05263         status = smb_set_file_unix_basic(conn, pdata, total_data,
05264                                 fsp, fname, psbuf);
05265         if (!NT_STATUS_IS_OK(status)) {
05266                 return status;
05267         }
05268 
05269         smb_fflags = IVAL(pdata, 108);
05270         smb_fmask = IVAL(pdata, 112);
05271 
05272         /* NB: We should only attempt to alter the file flags if the client
05273          * sends a non-zero mask.
05274          */
05275         if (smb_fmask != 0) {
05276                 int stat_fflags = 0;
05277 
05278                 if (!map_info2_flags_to_sbuf(psbuf, smb_fflags, smb_fmask,
05279                             &stat_fflags)) {
05280                         /* Client asked to alter a flag we don't understand. */
05281                         return NT_STATUS_INVALID_PARAMETER;
05282                 }
05283 
05284                 if (fsp && fsp->fh->fd != -1) {
05285                         /* XXX: we should be  using SMB_VFS_FCHFLAGS here. */
05286                         return NT_STATUS_NOT_SUPPORTED;
05287                 } else {
05288                         if (SMB_VFS_CHFLAGS(conn, fname, stat_fflags) != 0) {
05289                                 return map_nt_error_from_unix(errno);
05290                         }
05291                 }
05292         }
05293 
05294         /* XXX: need to add support for changing the create_time here. You
05295          * can do this for paths on Darwin with setattrlist(2). The right way
05296          * to hook this up is probably by extending the VFS utimes interface.
05297          */
05298 
05299         return NT_STATUS_OK;
05300 }
05301 
05302 /****************************************************************************
05303  Create a directory with POSIX semantics.
05304 ****************************************************************************/
05305 
05306 static NTSTATUS smb_posix_mkdir(connection_struct *conn,
05307                                 char **ppdata,
05308                                 int total_data,
05309                                 const char *fname,
05310                                 SMB_STRUCT_STAT *psbuf,
05311                                 int *pdata_return_size)
05312 {
05313         NTSTATUS status = NT_STATUS_OK;
05314         uint32 raw_unixmode = 0;
05315         uint32 mod_unixmode = 0;
05316         mode_t unixmode = (mode_t)0;
05317         files_struct *fsp = NULL;
05318         uint16 info_level_return = 0;
05319         int info;
05320         char *pdata = *ppdata;
05321 
05322         if (total_data < 18) {
05323                 return NT_STATUS_INVALID_PARAMETER;
05324         }
05325 
05326         raw_unixmode = IVAL(pdata,8);
05327         /* Next 4 bytes are not yet defined. */
05328 
05329         status = unix_perms_from_wire(conn, psbuf, raw_unixmode, PERM_NEW_DIR, &unixmode);
05330         if (!NT_STATUS_IS_OK(status)) {
05331                 return status;
05332         }
05333 
05334         mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
05335 
05336         DEBUG(10,("smb_posix_mkdir: file %s, mode 0%o\n",
05337                 fname, (unsigned int)unixmode ));
05338 
05339         status = open_directory(conn,
05340                                 fname,
05341                                 psbuf,
05342                                 FILE_READ_ATTRIBUTES, /* Just a stat open */
05343                                 FILE_SHARE_NONE, /* Ignored for stat opens */
05344                                 FILE_CREATE,
05345                                 0,
05346                                 mod_unixmode,
05347                                 &info,
05348                                 &fsp);
05349 
05350         if (NT_STATUS_IS_OK(status)) {
05351                 close_file(fsp, NORMAL_CLOSE);
05352         }
05353 
05354         info_level_return = SVAL(pdata,16);
05355  
05356         if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
05357                 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
05358         } else if (info_level_return ==  SMB_QUERY_FILE_UNIX_INFO2) {
05359                 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
05360         } else {
05361                 *pdata_return_size = 12;
05362         }
05363 
05364         /* Realloc the data size */
05365         *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
05366         if (*ppdata == NULL) {
05367                 *pdata_return_size = 0;
05368                 return NT_STATUS_NO_MEMORY;
05369         }
05370         pdata = *ppdata;
05371 
05372         SSVAL(pdata,0,NO_OPLOCK_RETURN);
05373         SSVAL(pdata,2,0); /* No fnum. */
05374         SIVAL(pdata,4,info); /* Was directory created. */
05375 
05376         switch (info_level_return) {
05377                 case SMB_QUERY_FILE_UNIX_BASIC:
05378                         SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
05379                         SSVAL(pdata,10,0); /* Padding. */
05380                         store_file_unix_basic(conn, pdata + 12, fsp, psbuf);
05381                         break;
05382                 case SMB_QUERY_FILE_UNIX_INFO2:
05383                         SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
05384                         SSVAL(pdata,10,0); /* Padding. */
05385                         store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf);
05386                         break;
05387                 default:
05388                         SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
05389                         SSVAL(pdata,10,0); /* Padding. */
05390                         break;
05391         }
05392 
05393         return status;
05394 }
05395 
05396 /****************************************************************************
05397  Open/Create a file with POSIX semantics.
05398 ****************************************************************************/
05399 
05400 static NTSTATUS smb_posix_open(connection_struct *conn,
05401                                 char **ppdata,
05402                                 int total_data,
05403                                 const char *fname,
05404                                 SMB_STRUCT_STAT *psbuf,
05405                                 int *pdata_return_size)
05406 {
05407         BOOL extended_oplock_granted = False;
05408         char *pdata = *ppdata;
05409         uint32 flags = 0;
05410         uint32 wire_open_mode = 0;
05411         uint32 raw_unixmode = 0;
05412         uint32 mod_unixmode = 0;
05413         uint32 create_disp = 0;
05414         uint32 access_mask = 0;
05415         uint32 create_options = 0;
05416         NTSTATUS status = NT_STATUS_OK;
05417         mode_t unixmode = (mode_t)0;
05418         files_struct *fsp = NULL;
05419         int oplock_request = 0;
05420         int info = 0;
05421         uint16 info_level_return = 0;
05422 
05423         if (total_data < 18) {
05424                 return NT_STATUS_INVALID_PARAMETER;
05425         }
05426 
05427         flags = IVAL(pdata,0);
05428         oplock_request = (flags & REQUEST_OPLOCK) ? EXCLUSIVE_OPLOCK : 0;
05429         if (oplock_request) {
05430                 oplock_request |= (flags & REQUEST_BATCH_OPLOCK) ? BATCH_OPLOCK : 0;
05431         }
05432 
05433         wire_open_mode = IVAL(pdata,4);
05434 
05435         if (wire_open_mode == (SMB_O_CREAT|SMB_O_DIRECTORY)) {
05436                 return smb_posix_mkdir(conn,
05437                                         ppdata,
05438                                         total_data,
05439                                         fname,
05440                                         psbuf,
05441                                         pdata_return_size);
05442         }
05443 
05444         switch (wire_open_mode & SMB_ACCMODE) {
05445                 case SMB_O_RDONLY:
05446                         access_mask = FILE_READ_DATA;
05447                         break;
05448                 case SMB_O_WRONLY:
05449                         access_mask = FILE_WRITE_DATA;
05450                         break;
05451                 case SMB_O_RDWR:
05452                         access_mask = FILE_READ_DATA|FILE_WRITE_DATA;
05453                         break;
05454                 default:
05455                         DEBUG(5,("smb_posix_open: invalid open mode 0x%x\n",
05456                                 (unsigned int)wire_open_mode ));
05457                         return NT_STATUS_INVALID_PARAMETER;
05458         }
05459 
05460         wire_open_mode &= ~SMB_ACCMODE;
05461 
05462         if((wire_open_mode & (SMB_O_CREAT | SMB_O_EXCL)) == (SMB_O_CREAT | SMB_O_EXCL)) {
05463                 create_disp = FILE_CREATE;
05464         } else if((wire_open_mode & (SMB_O_CREAT | SMB_O_TRUNC)) == (SMB_O_CREAT | SMB_O_TRUNC)) {
05465                 create_disp = FILE_OVERWRITE_IF;
05466         } else if((wire_open_mode & SMB_O_CREAT) == SMB_O_CREAT) {
05467                 create_disp = FILE_OPEN_IF;
05468         } else {
05469                 DEBUG(5,("smb_posix_open: invalid create mode 0x%x\n",
05470                         (unsigned int)wire_open_mode ));
05471                 return NT_STATUS_INVALID_PARAMETER;
05472         }
05473 
05474         raw_unixmode = IVAL(pdata,8);
05475         /* Next 4 bytes are not yet defined. */
05476 
05477         status = unix_perms_from_wire(conn,
05478                                 psbuf,
05479                                 raw_unixmode,
05480                                 VALID_STAT(*psbuf) ? PERM_EXISTING_FILE : PERM_NEW_FILE,
05481                                 &unixmode);
05482 
05483         if (!NT_STATUS_IS_OK(status)) {
05484                 return status;
05485         }
05486 
05487         mod_unixmode = (uint32)unixmode | FILE_FLAG_POSIX_SEMANTICS;
05488 
05489         if (wire_open_mode & SMB_O_SYNC) {
05490                 create_options |= FILE_WRITE_THROUGH;
05491         }
05492         if (wire_open_mode & SMB_O_APPEND) {
05493                 access_mask |= FILE_APPEND_DATA;
05494         }
05495         if (wire_open_mode & SMB_O_DIRECT) {
05496                 mod_unixmode |= FILE_FLAG_NO_BUFFERING;
05497         }
05498 
05499         DEBUG(10,("smb_posix_open: file %s, smb_posix_flags = %u, mode 0%o\n",
05500                 fname,
05501                 (unsigned int)wire_open_mode,
05502                 (unsigned int)unixmode ));
05503 
05504         status = open_file_ntcreate(conn,
05505                                 fname,
05506                                 psbuf,
05507                                 access_mask,
05508                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
05509                                 create_disp,
05510                                 0,              /* no create options yet. */
05511                                 mod_unixmode,
05512                                 oplock_request,
05513                                 &info,
05514                                 &fsp);
05515 
05516         if (!NT_STATUS_IS_OK(status)) {
05517                 return status;
05518         }
05519 
05520         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
05521                 extended_oplock_granted = True;
05522         }
05523 
05524         if(oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
05525                 extended_oplock_granted = True;
05526         }
05527 
05528         info_level_return = SVAL(pdata,16);
05529  
05530         /* Allocate the correct return size. */
05531 
05532         if (info_level_return == SMB_QUERY_FILE_UNIX_BASIC) {
05533                 *pdata_return_size = 12 + SMB_FILE_UNIX_BASIC_SIZE;
05534         } else if (info_level_return ==  SMB_QUERY_FILE_UNIX_INFO2) {
05535                 *pdata_return_size = 12 + SMB_FILE_UNIX_INFO2_SIZE;
05536         } else {
05537                 *pdata_return_size = 12;
05538         }
05539 
05540         /* Realloc the data size */
05541         *ppdata = (char *)SMB_REALLOC(*ppdata,*pdata_return_size);
05542         if (*ppdata == NULL) {
05543                 close_file(fsp,ERROR_CLOSE);
05544                 *pdata_return_size = 0;
05545                 return NT_STATUS_NO_MEMORY;
05546         }
05547         pdata = *ppdata;
05548 
05549         if (extended_oplock_granted) {
05550                 if (flags & REQUEST_BATCH_OPLOCK) {
05551                         SSVAL(pdata,0, BATCH_OPLOCK_RETURN);
05552                 } else {
05553                         SSVAL(pdata,0, EXCLUSIVE_OPLOCK_RETURN);
05554                 }
05555         } else if (fsp->oplock_type == LEVEL_II_OPLOCK) {
05556                 SSVAL(pdata,0, LEVEL_II_OPLOCK_RETURN);
05557         } else {
05558                 SSVAL(pdata,0,NO_OPLOCK_RETURN);
05559         }
05560 
05561         SSVAL(pdata,2,fsp->fnum);
05562         SIVAL(pdata,4,info); /* Was file created etc. */
05563 
05564         switch (info_level_return) {
05565                 case SMB_QUERY_FILE_UNIX_BASIC:
05566                         SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_BASIC);
05567                         SSVAL(pdata,10,0); /* padding. */
05568                         store_file_unix_basic(conn, pdata + 12, fsp, psbuf);
05569                         break;
05570                 case SMB_QUERY_FILE_UNIX_INFO2:
05571                         SSVAL(pdata,8,SMB_QUERY_FILE_UNIX_INFO2);
05572                         SSVAL(pdata,10,0); /* padding. */
05573                         store_file_unix_basic_info2(conn, pdata + 12, fsp, psbuf);
05574                         break;
05575                 default:
05576                         SSVAL(pdata,8,SMB_NO_INFO_LEVEL_RETURNED);
05577                         SSVAL(pdata,10,0); /* padding. */
05578                         break;
05579         }
05580         return NT_STATUS_OK;
05581 }
05582 
05583 /****************************************************************************
05584  Delete a file with POSIX semantics.
05585 ****************************************************************************/
05586 
05587 static NTSTATUS smb_posix_unlink(connection_struct *conn,
05588                                 const char *pdata,
05589                                 int total_data,
05590                                 const char *fname,
05591                                 SMB_STRUCT_STAT *psbuf)
05592 {
05593         NTSTATUS status = NT_STATUS_OK;
05594         files_struct *fsp = NULL;
05595         uint16 flags = 0;
05596         char del = 1;
05597         int info = 0;
05598         int i;
05599         struct share_mode_lock *lck = NULL;
05600 
05601         if (total_data < 2) {
05602                 return NT_STATUS_INVALID_PARAMETER;
05603         }
05604 
05605         flags = SVAL(pdata,0);
05606 
05607         if (!VALID_STAT(*psbuf)) {
05608                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
05609         }
05610 
05611         if ((flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) &&
05612                         !VALID_STAT_OF_DIR(*psbuf)) {
05613                 return NT_STATUS_NOT_A_DIRECTORY;
05614         }
05615 
05616         DEBUG(10,("smb_posix_unlink: %s %s\n",
05617                 (flags == SMB_POSIX_UNLINK_DIRECTORY_TARGET) ? "directory" : "file",
05618                 fname));
05619 
05620         if (VALID_STAT_OF_DIR(*psbuf)) {
05621                 status = open_directory(conn,
05622                                         fname,
05623                                         psbuf,
05624                                         DELETE_ACCESS,
05625                                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
05626                                         FILE_OPEN,
05627                                         0,
05628                                         FILE_FLAG_POSIX_SEMANTICS|0777,
05629                                         &info,
05630                                         &fsp);
05631         } else {
05632 
05633                 status = open_file_ntcreate(conn,
05634                                 fname,
05635                                 psbuf,
05636                                 DELETE_ACCESS,
05637                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
05638                                 FILE_OPEN,
05639                                 0,
05640                                 FILE_FLAG_POSIX_SEMANTICS|0777,
05641                                 0, /* No oplock, but break existing ones. */
05642                                 &info,
05643                                 &fsp);
05644         }
05645 
05646         if (!NT_STATUS_IS_OK(status)) {
05647                 return status;
05648         }
05649 
05650         /*
05651          * Don't lie to client. If we can't really delete due to
05652          * non-POSIX opens return SHARING_VIOLATION.
05653          */
05654 
05655         lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
05656         if (lck == NULL) {
05657                 DEBUG(0, ("smb_posix_unlink: Could not get share mode "
05658                         "lock for file %s\n", fsp->fsp_name));
05659                 close_file(fsp, NORMAL_CLOSE);
05660                 return NT_STATUS_INVALID_PARAMETER;
05661         }
05662 
05663         /*
05664          * See if others still have the file open. If this is the case, then
05665          * don't delete. If all opens are POSIX delete we can set the delete
05666          * on close disposition.
05667          */
05668         for (i=0; i<lck->num_share_modes; i++) {
05669                 struct share_mode_entry *e = &lck->share_modes[i];
05670                 if (is_valid_share_mode_entry(e)) {
05671                         if (e->flags & SHARE_MODE_FLAG_POSIX_OPEN) {
05672                                 continue;
05673                         }
05674                         /* Fail with sharing violation. */
05675                         close_file(fsp, NORMAL_CLOSE);
05676                         TALLOC_FREE(lck);
05677                         return NT_STATUS_SHARING_VIOLATION;
05678                 }
05679         }
05680 
05681         /*
05682          * Set the delete on close.
05683          */
05684         status = smb_set_file_disposition_info(conn,
05685                                                 &del,
05686                                                 1,
05687                                                 fsp,
05688                                                 fname,
05689                                                 psbuf);
05690 
05691         if (!NT_STATUS_IS_OK(status)) {
05692                 close_file(fsp, NORMAL_CLOSE);
05693                 TALLOC_FREE(lck);
05694                 return status;
05695         }
05696         TALLOC_FREE(lck);
05697         return close_file(fsp, NORMAL_CLOSE);
05698 }
05699 
05700 /****************************************************************************
05701  Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname).
05702 ****************************************************************************/
05703 
05704 static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
05705                                         unsigned int tran_call,
05706                                         char **pparams, int total_params, char **ppdata, int total_data,
05707                                         unsigned int max_data_bytes)
05708 {
05709         char *params = *pparams;
05710         char *pdata = *ppdata;
05711         uint16 info_level;
05712         SMB_STRUCT_STAT sbuf;
05713         pstring fname;
05714         files_struct *fsp = NULL;
05715         NTSTATUS status = NT_STATUS_OK;
05716         int data_return_size = 0;
05717 
05718         if (!params) {
05719                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
05720         }
05721 
05722         ZERO_STRUCT(sbuf);
05723 
05724         if (tran_call == TRANSACT2_SETFILEINFO) {
05725                 if (total_params < 4) {
05726                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
05727                 }
05728 
05729                 fsp = file_fsp(params,0);
05730                 info_level = SVAL(params,2);    
05731 
05732                 if(fsp && (fsp->is_directory || fsp->fh->fd == -1)) {
05733                         /*
05734                          * This is actually a SETFILEINFO on a directory
05735                          * handle (returned from an NT SMB). NT5.0 seems
05736                          * to do this call. JRA.
05737                          */
05738                         pstrcpy(fname, fsp->fsp_name);
05739                         if (INFO_LEVEL_IS_UNIX(info_level)) {
05740                                 /* Always do lstat for UNIX calls. */
05741                                 if (SMB_VFS_LSTAT(conn,fname,&sbuf)) {
05742                                         DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_LSTAT of %s failed (%s)\n",fname,strerror(errno)));
05743                                         return UNIXERROR(ERRDOS,ERRbadpath);
05744                                 }
05745                         } else {
05746                                 if (SMB_VFS_STAT(conn,fname,&sbuf) != 0) {
05747                                         DEBUG(3,("call_trans2setfilepathinfo: fileinfo of %s failed (%s)\n",fname,strerror(errno)));
05748                                         return UNIXERROR(ERRDOS,ERRbadpath);
05749                                 }
05750                         }
05751                 } else if (fsp && fsp->print_file) {
05752                         /*
05753                          * Doing a DELETE_ON_CLOSE should cancel a print job.
05754                          */
05755                         if ((info_level == SMB_SET_FILE_DISPOSITION_INFO) && CVAL(pdata,0)) {
05756                                 fsp->fh->private_options |= FILE_DELETE_ON_CLOSE;
05757 
05758                                 DEBUG(3,("call_trans2setfilepathinfo: Cancelling print job (%s)\n", fsp->fsp_name ));
05759         
05760                                 SSVAL(params,0,0);
05761                                 send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes);
05762                                 return(-1);
05763                         } else
05764                                 return (UNIXERROR(ERRDOS,ERRbadpath));
05765             } else {
05766                         /*
05767                          * Original code - this is an open file.
05768                          */
05769                         CHECK_FSP(fsp,conn);
05770 
05771                         pstrcpy(fname, fsp->fsp_name);
05772 
05773                         if (SMB_VFS_FSTAT(fsp, fsp->fh->fd, &sbuf) != 0) {
05774                                 DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n",fsp->fnum, strerror(errno)));
05775                                 return(UNIXERROR(ERRDOS,ERRbadfid));
05776                         }
05777                 }
05778         } else {
05779                 /* set path info */
05780                 if (total_params < 7) {
05781                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
05782                 }
05783 
05784                 info_level = SVAL(params,0);    
05785                 srvstr_get_path(inbuf, fname, &params[6], sizeof(fname), total_params - 6, STR_TERMINATE, &status);
05786                 if (!NT_STATUS_IS_OK(status)) {
05787                         return ERROR_NT(status);
05788                 }
05789 
05790                 status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
05791                 if (!NT_STATUS_IS_OK(status)) {
05792                         if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
05793                                 return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
05794                         }
05795                         return ERROR_NT(status);
05796                 }
05797 
05798                 status = unix_convert(conn, fname, False, NULL, &sbuf);
05799                 if (!NT_STATUS_IS_OK(status)) {
05800                         return ERROR_NT(status);
05801                 }
05802 
05803                 status = check_name(conn, fname);
05804                 if (!NT_STATUS_IS_OK(status)) {
05805                         return ERROR_NT(status);
05806                 }
05807 
05808                 if (INFO_LEVEL_IS_UNIX(info_level)) {
05809                         /*
05810                          * For CIFS UNIX extensions the target name may not exist.
05811                          */
05812 
05813                         /* Always do lstat for UNIX calls. */
05814                         SMB_VFS_LSTAT(conn,fname,&sbuf);
05815 
05816                 } else if (!VALID_STAT(sbuf) && SMB_VFS_STAT(conn,fname,&sbuf)) {
05817                         DEBUG(3,("call_trans2setfilepathinfo: SMB_VFS_STAT of %s failed (%s)\n",fname,strerror(errno)));
05818                         return UNIXERROR(ERRDOS,ERRbadpath);
05819                 }
05820         }
05821 
05822         if (!CAN_WRITE(conn)) {
05823                 return ERROR_DOS(ERRSRV,ERRaccess);
05824         }
05825 
05826         if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
05827                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
05828         }
05829 
05830         DEBUG(3,("call_trans2setfilepathinfo(%d) %s (fnum %d) info_level=%d totdata=%d\n",
05831                 tran_call,fname, fsp ? fsp->fnum : -1, info_level,total_data));
05832 
05833         /* Realloc the parameter size */
05834         *pparams = (char *)SMB_REALLOC(*pparams,2);
05835         if (*pparams == NULL) {
05836                 return ERROR_NT(NT_STATUS_NO_MEMORY);
05837         }
05838         params = *pparams;
05839 
05840         SSVAL(params,0,0);
05841 
05842         if (fsp && !null_timespec(fsp->pending_modtime)) {
05843                 /* the pending modtime overrides the current modtime */
05844                 set_mtimespec(&sbuf, fsp->pending_modtime);
05845         }
05846 
05847         switch (info_level) {
05848 
05849                 case SMB_INFO_STANDARD:
05850                 {
05851                         status = smb_set_info_standard(conn,
05852                                         pdata,
05853                                         total_data,
05854                                         fsp,
05855                                         fname,
05856                                         &sbuf);
05857                         break;
05858                 }
05859 
05860                 case SMB_INFO_SET_EA:
05861                 {
05862                         status = smb_info_set_ea(conn,
05863                                                 pdata,
05864                                                 total_data,
05865                                                 fsp,
05866                                                 fname);
05867                         break;
05868                 }
05869 
05870                 case SMB_SET_FILE_BASIC_INFO:
05871                 case SMB_FILE_BASIC_INFORMATION:
05872                 {
05873                         status = smb_set_file_basic_info(conn,
05874                                                         pdata,
05875                                                         total_data,
05876                                                         fsp,
05877                                                         fname,
05878                                                         &sbuf);
05879                         break;
05880                 }
05881 
05882                 case SMB_FILE_ALLOCATION_INFORMATION:
05883                 case SMB_SET_FILE_ALLOCATION_INFO:
05884                 {
05885                         status = smb_set_file_allocation_info(conn,
05886                                                                 pdata,
05887                                                                 total_data,
05888                                                                 fsp,
05889                                                                 fname,
05890                                                                 &sbuf);
05891                         break;
05892                 }
05893 
05894                 case SMB_FILE_END_OF_FILE_INFORMATION:
05895                 case SMB_SET_FILE_END_OF_FILE_INFO:
05896                 {
05897                         status = smb_set_file_end_of_file_info(conn,
05898                                                                 pdata,
05899                                                                 total_data,
05900                                                                 fsp,
05901                                                                 fname,
05902                                                                 &sbuf);
05903                         break;
05904                 }
05905 
05906                 case SMB_FILE_DISPOSITION_INFORMATION:
05907                 case SMB_SET_FILE_DISPOSITION_INFO: /* Set delete on close for open file. */
05908                 {
05909 #if 0
05910                         /* JRA - We used to just ignore this on a path ? 
05911                          * Shouldn't this be invalid level on a pathname
05912                          * based call ?
05913                          */
05914                         if (tran_call != TRANSACT2_SETFILEINFO) {
05915                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
05916                         }
05917 #endif
05918                         status = smb_set_file_disposition_info(conn,
05919                                                 pdata,
05920                                                 total_data,
05921                                                 fsp,
05922                                                 fname,
05923                                                 &sbuf);
05924                         break;
05925                 }
05926 
05927                 case SMB_FILE_POSITION_INFORMATION:
05928                 {
05929                         status = smb_file_position_information(conn,
05930                                                 pdata,
05931                                                 total_data,
05932                                                 fsp);
05933                         break;
05934                 }
05935 
05936                 /* From tridge Samba4 : 
05937                  * MODE_INFORMATION in setfileinfo (I have no
05938                  * idea what "mode information" on a file is - it takes a value of 0,
05939                  * 2, 4 or 6. What could it be?).
05940                  */
05941 
05942                 case SMB_FILE_MODE_INFORMATION:
05943                 {
05944                         status = smb_file_mode_information(conn,
05945                                                 pdata,
05946                                                 total_data);
05947                         break;
05948                 }
05949 
05950                 /*
05951                  * CIFS UNIX extensions.
05952                  */
05953 
05954                 case SMB_SET_FILE_UNIX_BASIC:
05955                 {
05956                         status = smb_set_file_unix_basic(conn,
05957                                                         pdata,
05958                                                         total_data,
05959                                                         fsp,
05960                                                         fname,
05961                                                         &sbuf);
05962                         break;
05963                 }
05964 
05965                 case SMB_SET_FILE_UNIX_INFO2:
05966                 {
05967                         status = smb_set_file_unix_info2(conn,
05968                                                         pdata,
05969                                                         total_data,
05970                                                         fsp,
05971                                                         fname,
05972                                                         &sbuf);
05973                         break;
05974                 }
05975 
05976                 case SMB_SET_FILE_UNIX_LINK:
05977                 {
05978                         if (tran_call != TRANSACT2_SETPATHINFO) {
05979                                 /* We must have a pathname for this. */
05980                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
05981                         }
05982                         status = smb_set_file_unix_link(conn,
05983                                                 inbuf,
05984                                                 pdata,
05985                                                 total_data,
05986                                                 fname);
05987                         break;
05988                 }
05989 
05990                 case SMB_SET_FILE_UNIX_HLINK:
05991                 {
05992                         if (tran_call != TRANSACT2_SETPATHINFO) {
05993                                 /* We must have a pathname for this. */
05994                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
05995                         }
05996                         status = smb_set_file_unix_hlink(conn,
05997                                                 inbuf,
05998                                                 outbuf,
05999                                                 pdata,
06000                                                 total_data,
06001                                                 fname);
06002                         break;
06003                 }
06004 
06005                 case SMB_FILE_RENAME_INFORMATION:
06006                 {
06007                         status = smb_file_rename_information(conn,
06008                                                         inbuf,
06009                                                         outbuf,
06010                                                         pdata,
06011                                                         total_data,
06012                                                         fsp,
06013                                                         fname);
06014                         break;
06015                 }
06016 
06017 #if defined(HAVE_POSIX_ACLS)
06018                 case SMB_SET_POSIX_ACL:
06019                 {
06020                         status = smb_set_posix_acl(conn,
06021                                                 pdata,
06022                                                 total_data,
06023                                                 fsp,
06024                                                 fname,
06025                                                 &sbuf);
06026                         break;
06027                 }
06028 #endif
06029 
06030                 case SMB_SET_POSIX_LOCK:
06031                 {
06032                         if (tran_call != TRANSACT2_SETFILEINFO) {
06033                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
06034                         }
06035                         status = smb_set_posix_lock(conn,
06036                                                 inbuf,
06037                                                 length,
06038                                                 pdata,
06039                                                 total_data,
06040                                                 fsp);
06041                         break;
06042                 }
06043 
06044                 case SMB_POSIX_PATH_OPEN:
06045                 {
06046                         if (tran_call != TRANSACT2_SETPATHINFO) {
06047                                 /* We must have a pathname for this. */
06048                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
06049                         }
06050 
06051                         status = smb_posix_open(conn,
06052                                                 ppdata,
06053                                                 total_data,
06054                                                 fname,
06055                                                 &sbuf,
06056                                                 &data_return_size);
06057                         break;
06058                 }
06059 
06060                 case SMB_POSIX_PATH_UNLINK:
06061                 {
06062                         if (tran_call != TRANSACT2_SETPATHINFO) {
06063                                 /* We must have a pathname for this. */
06064                                 return ERROR_NT(NT_STATUS_INVALID_LEVEL);
06065                         }
06066 
06067                         status = smb_posix_unlink(conn,
06068                                                 pdata,
06069                                                 total_data,
06070                                                 fname,
06071                                                 &sbuf);
06072                         break;
06073                 }
06074 
06075                 default:
06076                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
06077         }
06078 
06079         
06080         if (!NT_STATUS_IS_OK(status)) {
06081                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
06082                         /* We have re-scheduled this call. */
06083                         return -1;
06084                 }
06085                 if (blocking_lock_was_deferred(SVAL(inbuf,smb_mid))) {
06086                         /* We have re-scheduled this call. */
06087                         return -1;
06088                 }
06089                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
06090                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
06091                 }
06092                 if (info_level == SMB_POSIX_PATH_OPEN) {
06093                         return ERROR_OPEN(status);
06094                 }
06095                 return ERROR_NT(status);
06096         }
06097 
06098         SSVAL(params,0,0);
06099         send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, data_return_size, max_data_bytes);
06100   
06101         return -1;
06102 }
06103 
06104 /****************************************************************************
06105  Reply to a TRANS2_MKDIR (make directory with extended attributes).
06106 ****************************************************************************/
06107 
06108 static int call_trans2mkdir(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
06109                                         char **pparams, int total_params, char **ppdata, int total_data,
06110                                         unsigned int max_data_bytes)
06111 {
06112         char *params = *pparams;
06113         char *pdata = *ppdata;
06114         pstring directory;
06115         SMB_STRUCT_STAT sbuf;
06116         NTSTATUS status = NT_STATUS_OK;
06117         struct ea_list *ea_list = NULL;
06118 
06119         if (!CAN_WRITE(conn))
06120                 return ERROR_DOS(ERRSRV,ERRaccess);
06121 
06122         if (total_params < 5) {
06123                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06124         }
06125 
06126         srvstr_get_path(inbuf, directory, &params[4], sizeof(directory), total_params - 4, STR_TERMINATE, &status);
06127         if (!NT_STATUS_IS_OK(status)) {
06128                 return ERROR_NT(status);
06129         }
06130 
06131         DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
06132 
06133         status = unix_convert(conn, directory, False, NULL, &sbuf);
06134         if (!NT_STATUS_IS_OK(status)) {
06135                 return ERROR_NT(status);
06136         }
06137 
06138         status = check_name(conn, directory);
06139         if (!NT_STATUS_IS_OK(status)) {
06140                 DEBUG(5,("call_trans2mkdir error (%s)\n", nt_errstr(status)));
06141                 return ERROR_NT(status);
06142         }
06143 
06144         /* Any data in this call is an EA list. */
06145         if (total_data && (total_data != 4) && !lp_ea_support(SNUM(conn))) {
06146                 return ERROR_NT(NT_STATUS_EAS_NOT_SUPPORTED);
06147         }
06148 
06149         /*
06150          * OS/2 workplace shell seems to send SET_EA requests of "null"
06151          * length (4 bytes containing IVAL 4).
06152          * They seem to have no effect. Bug #3212. JRA.
06153          */
06154 
06155         if (total_data != 4) {
06156                 if (total_data < 10) {
06157                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06158                 }
06159 
06160                 if (IVAL(pdata,0) > total_data) {
06161                         DEBUG(10,("call_trans2mkdir: bad total data size (%u) > %u\n",
06162                                 IVAL(pdata,0), (unsigned int)total_data));
06163                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06164                 }
06165 
06166                 ea_list = read_ea_list(tmp_talloc_ctx(), pdata + 4,
06167                                        total_data - 4);
06168                 if (!ea_list) {
06169                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06170                 }
06171         } else if (IVAL(pdata,0) != 4) {
06172                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06173         }
06174 
06175         status = create_directory(conn, directory);
06176 
06177         if (!NT_STATUS_IS_OK(status)) {
06178                 return ERROR_NT(status);
06179         }
06180   
06181         /* Try and set any given EA. */
06182         if (ea_list) {
06183                 status = set_ea(conn, NULL, directory, ea_list);
06184                 if (!NT_STATUS_IS_OK(status)) {
06185                         return ERROR_NT(status);
06186                 }
06187         }
06188 
06189         /* Realloc the parameter and data sizes */
06190         *pparams = (char *)SMB_REALLOC(*pparams,2);
06191         if(*pparams == NULL) {
06192                 return ERROR_NT(NT_STATUS_NO_MEMORY);
06193         }
06194         params = *pparams;
06195 
06196         SSVAL(params,0,0);
06197 
06198         send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0, max_data_bytes);
06199   
06200         return(-1);
06201 }
06202 
06203 /****************************************************************************
06204  Reply to a TRANS2_FINDNOTIFYFIRST (start monitoring a directory for changes).
06205  We don't actually do this - we just send a null response.
06206 ****************************************************************************/
06207 
06208 static int call_trans2findnotifyfirst(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
06209                                         char **pparams, int total_params, char **ppdata, int total_data,
06210                                         unsigned int max_data_bytes)
06211 {
06212         static uint16 fnf_handle = 257;
06213         char *params = *pparams;
06214         uint16 info_level;
06215 
06216         if (total_params < 6) {
06217                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06218         }
06219 
06220         info_level = SVAL(params,4);
06221         DEBUG(3,("call_trans2findnotifyfirst - info_level %d\n", info_level));
06222 
06223         switch (info_level) {
06224                 case 1:
06225                 case 2:
06226                         break;
06227                 default:
06228                         return ERROR_NT(NT_STATUS_INVALID_LEVEL);
06229         }
06230 
06231         /* Realloc the parameter and data sizes */
06232         *pparams = (char *)SMB_REALLOC(*pparams,6);
06233         if (*pparams == NULL) {
06234                 return ERROR_NT(NT_STATUS_NO_MEMORY);
06235         }
06236         params = *pparams;
06237 
06238         SSVAL(params,0,fnf_handle);
06239         SSVAL(params,2,0); /* No changes */
06240         SSVAL(params,4,0); /* No EA errors */
06241 
06242         fnf_handle++;
06243 
06244         if(fnf_handle == 0)
06245                 fnf_handle = 257;
06246 
06247         send_trans2_replies(outbuf, bufsize, params, 6, *ppdata, 0, max_data_bytes);
06248   
06249         return(-1);
06250 }
06251 
06252 /****************************************************************************
06253  Reply to a TRANS2_FINDNOTIFYNEXT (continue monitoring a directory for 
06254  changes). Currently this does nothing.
06255 ****************************************************************************/
06256 
06257 static int call_trans2findnotifynext(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize,
06258                                         char **pparams, int total_params, char **ppdata, int total_data,
06259                                         unsigned int max_data_bytes)
06260 {
06261         char *params = *pparams;
06262 
06263         DEBUG(3,("call_trans2findnotifynext\n"));
06264 
06265         /* Realloc the parameter and data sizes */
06266         *pparams = (char *)SMB_REALLOC(*pparams,4);
06267         if (*pparams == NULL) {
06268                 return ERROR_NT(NT_STATUS_NO_MEMORY);
06269         }
06270         params = *pparams;
06271 
06272         SSVAL(params,0,0); /* No changes */
06273         SSVAL(params,2,0); /* No EA errors */
06274 
06275         send_trans2_replies(outbuf, bufsize, params, 4, *ppdata, 0, max_data_bytes);
06276   
06277         return(-1);
06278 }
06279 
06280 /****************************************************************************
06281  Reply to a TRANS2_GET_DFS_REFERRAL - Shirish Kalele <kalele@veritas.com>.
06282 ****************************************************************************/
06283 
06284 static int call_trans2getdfsreferral(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
06285                                         char **pparams, int total_params, char **ppdata, int total_data,
06286                                         unsigned int max_data_bytes)
06287 {
06288         char *params = *pparams;
06289         pstring pathname;
06290         int reply_size = 0;
06291         int max_referral_level;
06292         NTSTATUS status = NT_STATUS_OK;
06293 
06294         DEBUG(10,("call_trans2getdfsreferral\n"));
06295 
06296         if (total_params < 3) {
06297                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06298         }
06299 
06300         max_referral_level = SVAL(params,0);
06301 
06302         if(!lp_host_msdfs())
06303                 return ERROR_DOS(ERRDOS,ERRbadfunc);
06304 
06305         srvstr_pull(inbuf, pathname, &params[2], sizeof(pathname), total_params - 2, STR_TERMINATE);
06306         if((reply_size = setup_dfs_referral(conn, pathname,max_referral_level,ppdata,&status)) < 0)
06307                 return ERROR_NT(status);
06308     
06309         SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_DFS_PATHNAMES);
06310         send_trans2_replies(outbuf,bufsize,0,0,*ppdata,reply_size, max_data_bytes);
06311 
06312         return(-1);
06313 }
06314 
06315 #define LMCAT_SPL       0x53
06316 #define LMFUNC_GETJOBID 0x60
06317 
06318 /****************************************************************************
06319  Reply to a TRANS2_IOCTL - used for OS/2 printing.
06320 ****************************************************************************/
06321 
06322 static int call_trans2ioctl(connection_struct *conn, char* inbuf, char* outbuf, int length, int bufsize,
06323                                         char **pparams, int total_params, char **ppdata, int total_data,
06324                                         unsigned int max_data_bytes)
06325 {
06326         char *pdata = *ppdata;
06327         files_struct *fsp = file_fsp(inbuf,smb_vwv15);
06328 
06329         /* check for an invalid fid before proceeding */
06330         
06331         if (!fsp)                                
06332                 return(ERROR_DOS(ERRDOS,ERRbadfid));  
06333 
06334         if ((SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
06335                         (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
06336                 *ppdata = (char *)SMB_REALLOC(*ppdata, 32);
06337                 if (*ppdata == NULL) {
06338                         return ERROR_NT(NT_STATUS_NO_MEMORY);
06339                 }
06340                 pdata = *ppdata;
06341 
06342                 /* NOTE - THIS IS ASCII ONLY AT THE MOMENT - NOT SURE IF OS/2
06343                         CAN ACCEPT THIS IN UNICODE. JRA. */
06344 
06345                 SSVAL(pdata,0,fsp->rap_print_jobid);                     /* Job number */
06346                 srvstr_push( outbuf, pdata + 2, global_myname(), 15, STR_ASCII|STR_TERMINATE); /* Our NetBIOS name */
06347                 srvstr_push( outbuf, pdata+18, lp_servicename(SNUM(conn)), 13, STR_ASCII|STR_TERMINATE); /* Service name */
06348                 send_trans2_replies(outbuf,bufsize,*pparams,0,*ppdata,32, max_data_bytes);
06349                 return(-1);
06350         } else {
06351                 DEBUG(2,("Unknown TRANS2_IOCTL\n"));
06352                 return ERROR_DOS(ERRSRV,ERRerror);
06353         }
06354 }
06355 
06356 /****************************************************************************
06357  Reply to a SMBfindclose (stop trans2 directory search).
06358 ****************************************************************************/
06359 
06360 int reply_findclose(connection_struct *conn,
06361                     char *inbuf,char *outbuf,int length,int bufsize)
06362 {
06363         int outsize = 0;
06364         int dptr_num=SVALS(inbuf,smb_vwv0);
06365         START_PROFILE(SMBfindclose);
06366 
06367         DEBUG(3,("reply_findclose, dptr_num = %d\n", dptr_num));
06368 
06369         dptr_close(&dptr_num);
06370 
06371         outsize = set_message(outbuf,0,0,False);
06372 
06373         DEBUG(3,("SMBfindclose dptr_num = %d\n", dptr_num));
06374 
06375         END_PROFILE(SMBfindclose);
06376         return(outsize);
06377 }
06378 
06379 /****************************************************************************
06380  Reply to a SMBfindnclose (stop FINDNOTIFYFIRST directory search).
06381 ****************************************************************************/
06382 
06383 int reply_findnclose(connection_struct *conn, 
06384                      char *inbuf,char *outbuf,int length,int bufsize)
06385 {
06386         int outsize = 0;
06387         int dptr_num= -1;
06388         START_PROFILE(SMBfindnclose);
06389         
06390         dptr_num = SVAL(inbuf,smb_vwv0);
06391 
06392         DEBUG(3,("reply_findnclose, dptr_num = %d\n", dptr_num));
06393 
06394         /* We never give out valid handles for a 
06395            findnotifyfirst - so any dptr_num is ok here. 
06396            Just ignore it. */
06397 
06398         outsize = set_message(outbuf,0,0,False);
06399 
06400         DEBUG(3,("SMB_findnclose dptr_num = %d\n", dptr_num));
06401 
06402         END_PROFILE(SMBfindnclose);
06403         return(outsize);
06404 }
06405 
06406 int handle_trans2(connection_struct *conn,
06407                   struct trans_state *state,
06408                   char *inbuf, char *outbuf, int size, int bufsize)
06409 {
06410         int outsize;
06411 
06412         if (Protocol >= PROTOCOL_NT1) {
06413                 SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | 0x40); /* IS_LONG_NAME */
06414         }
06415 
06416         /* Now we must call the relevant TRANS2 function */
06417         switch(state->call)  {
06418         case TRANSACT2_OPEN:
06419         {
06420                 START_PROFILE(Trans2_open);
06421                 outsize = call_trans2open(
06422                         conn, inbuf, outbuf, bufsize, 
06423                         &state->param, state->total_param,
06424                         &state->data, state->total_data,
06425                         state->max_data_return);
06426                 END_PROFILE(Trans2_open);
06427                 break;
06428         }
06429 
06430         case TRANSACT2_FINDFIRST:
06431         {
06432                 START_PROFILE(Trans2_findfirst);
06433                 outsize = call_trans2findfirst(
06434                         conn, inbuf, outbuf, bufsize,
06435                         &state->param, state->total_param,
06436                         &state->data, state->total_data,
06437                         state->max_data_return);
06438                 END_PROFILE(Trans2_findfirst);
06439                 break;
06440         }
06441 
06442         case TRANSACT2_FINDNEXT:
06443         {
06444                 START_PROFILE(Trans2_findnext);
06445                 outsize = call_trans2findnext(
06446                         conn, inbuf, outbuf, size, bufsize, 
06447                         &state->param, state->total_param,
06448                         &state->data, state->total_data,
06449                         state->max_data_return);
06450                 END_PROFILE(Trans2_findnext);
06451                 break;
06452         }
06453 
06454         case TRANSACT2_QFSINFO:
06455         {
06456                 START_PROFILE(Trans2_qfsinfo);
06457                 outsize = call_trans2qfsinfo(
06458                         conn, inbuf, outbuf, size, bufsize,
06459                         &state->param, state->total_param,
06460                         &state->data, state->total_data,
06461                         state->max_data_return);
06462                 END_PROFILE(Trans2_qfsinfo);
06463             break;
06464         }
06465 
06466         case TRANSACT2_SETFSINFO:
06467         {
06468                 START_PROFILE(Trans2_setfsinfo);
06469                 outsize = call_trans2setfsinfo(
06470                         conn, inbuf, outbuf, size, bufsize, 
06471                         &state->param, state->total_param,
06472                         &state->data, state->total_data,
06473                         state->max_data_return);
06474                 END_PROFILE(Trans2_setfsinfo);
06475                 break;
06476         }
06477 
06478         case TRANSACT2_QPATHINFO:
06479         case TRANSACT2_QFILEINFO:
06480         {
06481                 START_PROFILE(Trans2_qpathinfo);
06482                 outsize = call_trans2qfilepathinfo(
06483                         conn, inbuf, outbuf, size, bufsize, state->call,
06484                         &state->param, state->total_param,
06485                         &state->data, state->total_data,
06486                         state->max_data_return);
06487                 END_PROFILE(Trans2_qpathinfo);
06488                 break;
06489         }
06490 
06491         case TRANSACT2_SETPATHINFO:
06492         case TRANSACT2_SETFILEINFO:
06493         {
06494                 START_PROFILE(Trans2_setpathinfo);
06495                 outsize = call_trans2setfilepathinfo(
06496                         conn, inbuf, outbuf, size, bufsize, state->call,
06497                         &state->param, state->total_param,
06498                         &state->data, state->total_data,
06499                         state->max_data_return);
06500                 END_PROFILE(Trans2_setpathinfo);
06501                 break;
06502         }
06503 
06504         case TRANSACT2_FINDNOTIFYFIRST:
06505         {
06506                 START_PROFILE(Trans2_findnotifyfirst);
06507                 outsize = call_trans2findnotifyfirst(
06508                         conn, inbuf, outbuf, size, bufsize, 
06509                         &state->param, state->total_param,
06510                         &state->data, state->total_data,
06511                         state->max_data_return);
06512                 END_PROFILE(Trans2_findnotifyfirst);
06513                 break;
06514         }
06515 
06516         case TRANSACT2_FINDNOTIFYNEXT:
06517         {
06518                 START_PROFILE(Trans2_findnotifynext);
06519                 outsize = call_trans2findnotifynext(
06520                         conn, inbuf, outbuf, size, bufsize, 
06521                         &state->param, state->total_param,
06522                         &state->data, state->total_data,
06523                         state->max_data_return);
06524                 END_PROFILE(Trans2_findnotifynext);
06525                 break;
06526         }
06527 
06528         case TRANSACT2_MKDIR:
06529         {
06530                 START_PROFILE(Trans2_mkdir);
06531                 outsize = call_trans2mkdir(
06532                         conn, inbuf, outbuf, size, bufsize,
06533                         &state->param, state->total_param,
06534                         &state->data, state->total_data,
06535                         state->max_data_return);
06536                 END_PROFILE(Trans2_mkdir);
06537                 break;
06538         }
06539 
06540         case TRANSACT2_GET_DFS_REFERRAL:
06541         {
06542                 START_PROFILE(Trans2_get_dfs_referral);
06543                 outsize = call_trans2getdfsreferral(
06544                         conn, inbuf, outbuf, size, bufsize,
06545                         &state->param, state->total_param,
06546                         &state->data, state->total_data,
06547                         state->max_data_return);
06548                 END_PROFILE(Trans2_get_dfs_referral);
06549                 break;
06550         }
06551 
06552         case TRANSACT2_IOCTL:
06553         {
06554                 START_PROFILE(Trans2_ioctl);
06555                 outsize = call_trans2ioctl(
06556                         conn, inbuf, outbuf, size, bufsize,
06557                         &state->param, state->total_param,
06558                         &state->data, state->total_data,
06559                         state->max_data_return);
06560                 END_PROFILE(Trans2_ioctl);
06561                 break;
06562         }
06563 
06564         default:
06565                 /* Error in request */
06566                 DEBUG(2,("Unknown request %d in trans2 call\n", state->call));
06567                 outsize = ERROR_DOS(ERRSRV,ERRerror);
06568         }
06569 
06570         return outsize;
06571 }
06572 
06573 /****************************************************************************
06574  Reply to a SMBtrans2.
06575  ****************************************************************************/
06576 
06577 int reply_trans2(connection_struct *conn, char *inbuf,char *outbuf,
06578                  int size, int bufsize)
06579 {
06580         int outsize = 0;
06581         unsigned int dsoff = SVAL(inbuf, smb_dsoff);
06582         unsigned int dscnt = SVAL(inbuf, smb_dscnt);
06583         unsigned int psoff = SVAL(inbuf, smb_psoff);
06584         unsigned int pscnt = SVAL(inbuf, smb_pscnt);
06585         unsigned int tran_call = SVAL(inbuf, smb_setup0);
06586         unsigned int av_size = size-4;
06587         struct trans_state *state;
06588         NTSTATUS result;
06589 
06590         START_PROFILE(SMBtrans2);
06591 
06592         result = allow_new_trans(conn->pending_trans, SVAL(inbuf, smb_mid));
06593         if (!NT_STATUS_IS_OK(result)) {
06594                 DEBUG(2, ("Got invalid trans2 request: %s\n",
06595                           nt_errstr(result)));
06596                 END_PROFILE(SMBtrans2);
06597                 return ERROR_NT(result);
06598         }
06599 
06600         if (IS_IPC(conn) && (tran_call != TRANSACT2_OPEN)
06601             && (tran_call != TRANSACT2_GET_DFS_REFERRAL)) {
06602                 END_PROFILE(SMBtrans2);
06603                 return ERROR_DOS(ERRSRV,ERRaccess);
06604         }
06605 
06606         if ((state = TALLOC_P(conn->mem_ctx, struct trans_state)) == NULL) {
06607                 DEBUG(0, ("talloc failed\n"));
06608                 END_PROFILE(SMBtrans2);
06609                 return ERROR_NT(NT_STATUS_NO_MEMORY);
06610         }
06611 
06612         state->cmd = SMBtrans2;
06613 
06614         state->mid = SVAL(inbuf, smb_mid);
06615         state->vuid = SVAL(inbuf, smb_uid);
06616         state->setup_count = SVAL(inbuf, smb_suwcnt);
06617         state->setup = NULL;
06618         state->total_param = SVAL(inbuf, smb_tpscnt);
06619         state->param = NULL;
06620         state->total_data =  SVAL(inbuf, smb_tdscnt);
06621         state->data = NULL;
06622         state->max_param_return = SVAL(inbuf, smb_mprcnt);
06623         state->max_data_return  = SVAL(inbuf, smb_mdrcnt);
06624         state->max_setup_return = SVAL(inbuf, smb_msrcnt);
06625         state->close_on_completion = BITSETW(inbuf+smb_vwv5,0);
06626         state->one_way = BITSETW(inbuf+smb_vwv5,1);
06627 
06628         state->call = tran_call;
06629 
06630         /* All trans2 messages we handle have smb_sucnt == 1 - ensure this
06631            is so as a sanity check */
06632         if (state->setup_count != 1) {
06633                 /*
06634                  * Need to have rc=0 for ioctl to get job id for OS/2.
06635                  *  Network printing will fail if function is not successful.
06636                  *  Similar function in reply.c will be used if protocol
06637                  *  is LANMAN1.0 instead of LM1.2X002.
06638                  *  Until DosPrintSetJobInfo with PRJINFO3 is supported,
06639                  *  outbuf doesn't have to be set(only job id is used).
06640                  */
06641                 if ( (state->setup_count == 4) && (tran_call == TRANSACT2_IOCTL) &&
06642                                 (SVAL(inbuf,(smb_setup+4)) == LMCAT_SPL) &&
06643                                 (SVAL(inbuf,(smb_setup+6)) == LMFUNC_GETJOBID)) {
06644                         DEBUG(2,("Got Trans2 DevIOctl jobid\n"));
06645                 } else {
06646                         DEBUG(2,("Invalid smb_sucnt in trans2 call(%u)\n",state->setup_count));
06647                         DEBUG(2,("Transaction is %d\n",tran_call));
06648                         TALLOC_FREE(state);
06649                         END_PROFILE(SMBtrans2);
06650                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06651                 }
06652         }
06653 
06654         if ((dscnt > state->total_data) || (pscnt > state->total_param))
06655                 goto bad_param;
06656 
06657         if (state->total_data) {
06658                 /* Can't use talloc here, the core routines do realloc on the
06659                  * params and data. */
06660                 state->data = (char *)SMB_MALLOC(state->total_data);
06661                 if (state->data == NULL) {
06662                         DEBUG(0,("reply_trans2: data malloc fail for %u "
06663                                  "bytes !\n", (unsigned int)state->total_data));
06664                         TALLOC_FREE(state);
06665                         END_PROFILE(SMBtrans2);
06666                         return(ERROR_DOS(ERRDOS,ERRnomem));
06667                 }
06668 
06669                 if (dscnt > state->total_data ||
06670                                 dsoff+dscnt < dsoff) {
06671                         goto bad_param;
06672                 }
06673 
06674                 if (dsoff > av_size ||
06675                                 dscnt > av_size ||
06676                                 dsoff+dscnt > av_size) {
06677                                 goto bad_param;
06678                 }
06679 
06680                 memcpy(state->data,smb_base(inbuf)+dsoff,dscnt);
06681         }
06682 
06683         if (state->total_param) {
06684                 /* Can't use talloc here, the core routines do realloc on the
06685                  * params and data. */
06686                 state->param = (char *)SMB_MALLOC(state->total_param);
06687                 if (state->param == NULL) {
06688                         DEBUG(0,("reply_trans: param malloc fail for %u "
06689                                  "bytes !\n", (unsigned int)state->total_param));
06690                         SAFE_FREE(state->data);
06691                         TALLOC_FREE(state);
06692                         END_PROFILE(SMBtrans2);
06693                         return(ERROR_DOS(ERRDOS,ERRnomem));
06694                 } 
06695 
06696                 if (pscnt > state->total_param ||
06697                                 psoff+pscnt < psoff) {
06698                         goto bad_param;
06699                 }
06700 
06701                 if (psoff > av_size ||
06702                                 pscnt > av_size ||
06703                                 psoff+pscnt > av_size) {
06704                         goto bad_param;
06705                 }
06706 
06707                 memcpy(state->param,smb_base(inbuf)+psoff,pscnt);
06708         }
06709 
06710         state->received_data  = dscnt;
06711         state->received_param = pscnt;
06712 
06713         if ((state->received_param == state->total_param) &&
06714             (state->received_data == state->total_data)) {
06715 
06716                 outsize = handle_trans2(conn, state, inbuf, outbuf,
06717                                         size, bufsize);
06718                 SAFE_FREE(state->data);
06719                 SAFE_FREE(state->param);
06720                 TALLOC_FREE(state);
06721                 END_PROFILE(SMBtrans2);
06722                 return outsize;
06723         }
06724 
06725         DLIST_ADD(conn->pending_trans, state);
06726 
06727         /* We need to send an interim response then receive the rest
06728            of the parameter/data bytes */
06729         outsize = set_message(outbuf,0,0,False);
06730         show_msg(outbuf);
06731         END_PROFILE(SMBtrans2);
06732         return outsize;
06733 
06734   bad_param:
06735 
06736         DEBUG(0,("reply_trans2: invalid trans parameters\n"));
06737         SAFE_FREE(state->data);
06738         SAFE_FREE(state->param);
06739         TALLOC_FREE(state);
06740         END_PROFILE(SMBtrans2);
06741         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06742 }
06743 
06744 
06745 /****************************************************************************
06746  Reply to a SMBtranss2
06747  ****************************************************************************/
06748 
06749 int reply_transs2(connection_struct *conn,
06750                   char *inbuf,char *outbuf,int size,int bufsize)
06751 {
06752         int outsize = 0;
06753         unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
06754         unsigned int av_size = size-4;
06755         struct trans_state *state;
06756 
06757         START_PROFILE(SMBtranss2);
06758 
06759         show_msg(inbuf);
06760 
06761         for (state = conn->pending_trans; state != NULL;
06762              state = state->next) {
06763                 if (state->mid == SVAL(inbuf,smb_mid)) {
06764                         break;
06765                 }
06766         }
06767 
06768         if ((state == NULL) || (state->cmd != SMBtrans2)) {
06769                 END_PROFILE(SMBtranss2);
06770                 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06771         }
06772 
06773         /* Revise state->total_param and state->total_data in case they have
06774            changed downwards */
06775 
06776         if (SVAL(inbuf, smb_tpscnt) < state->total_param)
06777                 state->total_param = SVAL(inbuf, smb_tpscnt);
06778         if (SVAL(inbuf, smb_tdscnt) < state->total_data)
06779                 state->total_data = SVAL(inbuf, smb_tdscnt);
06780 
06781         pcnt = SVAL(inbuf, smb_spscnt);
06782         poff = SVAL(inbuf, smb_spsoff);
06783         pdisp = SVAL(inbuf, smb_spsdisp);
06784 
06785         dcnt = SVAL(inbuf, smb_sdscnt);
06786         doff = SVAL(inbuf, smb_sdsoff);
06787         ddisp = SVAL(inbuf, smb_sdsdisp);
06788 
06789         state->received_param += pcnt;
06790         state->received_data += dcnt;
06791                 
06792         if ((state->received_data > state->total_data) ||
06793             (state->received_param > state->total_param))
06794                 goto bad_param;
06795 
06796         if (pcnt) {
06797                 if (pdisp > state->total_param ||
06798                                 pcnt > state->total_param ||
06799                                 pdisp+pcnt > state->total_param ||
06800                                 pdisp+pcnt < pdisp) {
06801                         goto bad_param;
06802                 }
06803 
06804                 if (poff > av_size ||
06805                                 pcnt > av_size ||
06806                                 poff+pcnt > av_size ||
06807                                 poff+pcnt < poff) {
06808                         goto bad_param;
06809                 }
06810 
06811                 memcpy(state->param+pdisp,smb_base(inbuf)+poff,
06812                        pcnt);
06813         }
06814 
06815         if (dcnt) {
06816                 if (ddisp > state->total_data ||
06817                                 dcnt > state->total_data ||
06818                                 ddisp+dcnt > state->total_data ||
06819                                 ddisp+dcnt < ddisp) {
06820                         goto bad_param;
06821                 }
06822 
06823                 if (doff > av_size ||
06824                                 dcnt > av_size ||
06825                                 doff+dcnt > av_size ||
06826                                 doff+dcnt < doff) {
06827                         goto bad_param;
06828                 }
06829 
06830                 memcpy(state->data+ddisp, smb_base(inbuf)+doff,
06831                        dcnt);      
06832         }
06833 
06834         if ((state->received_param < state->total_param) ||
06835             (state->received_data < state->total_data)) {
06836                 END_PROFILE(SMBtranss2);
06837                 return -1;
06838         }
06839 
06840         /* construct_reply_common has done us the favor to pre-fill the
06841          * command field with SMBtranss2 which is wrong :-)
06842          */
06843         SCVAL(outbuf,smb_com,SMBtrans2);
06844 
06845         outsize = handle_trans2(conn, state, inbuf, outbuf, size, bufsize);
06846 
06847         DLIST_REMOVE(conn->pending_trans, state);
06848         SAFE_FREE(state->data);
06849         SAFE_FREE(state->param);
06850         TALLOC_FREE(state);
06851 
06852         if (outsize == 0) {
06853                 END_PROFILE(SMBtranss2);
06854                 return(ERROR_DOS(ERRSRV,ERRnosupport));
06855         }
06856         
06857         END_PROFILE(SMBtranss2);
06858         return(outsize);
06859 
06860   bad_param:
06861 
06862         DEBUG(0,("reply_transs2: invalid trans parameters\n"));
06863         DLIST_REMOVE(conn->pending_trans, state);
06864         SAFE_FREE(state->data);
06865         SAFE_FREE(state->param);
06866         TALLOC_FREE(state);
06867         END_PROFILE(SMBtranss2);
06868         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
06869 }

Sambaに対してSat Aug 29 21:23:26 2009に生成されました。  doxygen 1.4.7