r8219: Merge the new open code from HEAD to 3.0. Haven't yet run the torture
[samba.git] / source3 / smbd / dosmode.c
index 3a3a6e6fdb052fd94e993f80275cc3e43cc1a24e..a2bc424b8e751734ed075146526973218ed3875d 100644 (file)
 
 #include "includes.h"
 
+static int set_sparse_flag(const SMB_STRUCT_STAT * const sbuf)
+{
+#if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
+       if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
+               return FILE_ATTRIBUTE_SPARSE;
+       }
+#endif
+       return 0;
+}
+
 /****************************************************************************
  Change a dos mode to a unix mode.
     Base permission for files:
-         if inheriting
+         if creating file and inheriting
            apply read/write bits from parent directory.
          else   
            everybody gets read bit set
@@ -43,7 +53,7 @@
          }
 ****************************************************************************/
 
-mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname)
+mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname, BOOL creating_file)
 {
        mode_t result = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH);
        mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */
@@ -52,7 +62,7 @@ mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname)
                result &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
        }
 
-       if (fname && lp_inherit_perms(SNUM(conn))) {
+       if (fname && creating_file && lp_inherit_perms(SNUM(conn))) {
                char *dname;
                SMB_STRUCT_STAT sbuf;
 
@@ -116,13 +126,18 @@ mode_t unix_mode(connection_struct *conn, int dosmode, const char *fname)
  Change a unix mode to a dos mode.
 ****************************************************************************/
 
-uint32 dos_mode_from_sbuf(connection_struct *conn, SMB_STRUCT_STAT *sbuf)
+uint32 dos_mode_from_sbuf(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf)
 {
        int result = 0;
 
-       if ((sbuf->st_mode & S_IWUSR) == 0)
+       if (lp_acl_check_permissions(SNUM(conn))) {
+               if (!can_write_to_file(conn, path, sbuf)) {
+                       result |= aRONLY;
+               }
+       } else if ((sbuf->st_mode & S_IWUSR) == 0) {
                result |= aRONLY;
-       
+       }
+
        if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
                result |= aARCH;
 
@@ -135,11 +150,7 @@ uint32 dos_mode_from_sbuf(connection_struct *conn, SMB_STRUCT_STAT *sbuf)
        if (S_ISDIR(sbuf->st_mode))
                result = aDIR | (result & aRONLY);
 
-#if defined (HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE)
-       if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)STAT_ST_BLOCKSIZE) {
-               result |= FILE_ATTRIBUTE_SPARSE;
-       }
-#endif
+       result |= set_sparse_flag(sbuf);
  
 #ifdef S_ISLNK
 #if LINKS_READ_ONLY
@@ -288,10 +299,11 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
 
        /* Get the DOS attributes from an EA by preference. */
        if (get_ea_dos_attribute(conn, path, sbuf, &result)) {
+               result |= set_sparse_flag(sbuf);
                return result;
        }
 
-       result = dos_mode_from_sbuf(conn, sbuf);
+       result = dos_mode_from_sbuf(conn, path, sbuf);
 
        /* Now do any modifications that depend on the path name. */
        /* hide files with a name starting with a . */
@@ -329,7 +341,7 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
  chmod a file - but preserve some bits.
 ********************************************************************/
 
-int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, SMB_STRUCT_STAT *st)
+int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode, SMB_STRUCT_STAT *st, BOOL creating_file)
 {
        SMB_STRUCT_STAT st1;
        int mask=0;
@@ -338,15 +350,13 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode,
        int ret = -1;
 
        DEBUG(10,("file_set_dosmode: setting dos mode 0x%x on file %s\n", dosmode, fname));
-       if (!st) {
+       if (!st || (st && !VALID_STAT(*st))) {
                st = &st1;
                if (SMB_VFS_STAT(conn,fname,st))
                        return(-1);
        }
 
-       if (!get_acl_group_bits(conn, fname, &st->st_mode)) {
-               return(-1);
-       }
+       get_acl_group_bits(conn, fname, &st->st_mode);
 
        if (S_ISDIR(st->st_mode))
                dosmode |= aDIR;
@@ -361,7 +371,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode,
                return 0;
        }
 
-       unixmode = unix_mode(conn,dosmode,fname);
+       unixmode = unix_mode(conn,dosmode,fname, creating_file);
 
        /* preserve the s bits */
        mask |= (S_ISUID | S_ISGID);
@@ -420,7 +430,7 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode,
                if (!fsp)
                        return -1;
                become_root();
-               ret = SMB_VFS_FCHMOD(fsp, fsp->fd, unixmode);
+               ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode);
                unbecome_root();
                close_file_fchmod(fsp);
        }
@@ -433,13 +443,13 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode,
  than POSIX.
 *******************************************************************/
 
-int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
+int file_utime(connection_struct *conn, const char *fname, struct utimbuf *times)
 {
-       extern struct current_user current_user;
-       SMB_STRUCT_STAT sb;
+       SMB_STRUCT_STAT sbuf;
        int ret = -1;
 
        errno = 0;
+       ZERO_STRUCT(sbuf);
 
        if(SMB_VFS_UTIME(conn,fname, times) == 0)
                return 0;
@@ -456,21 +466,12 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
           (as DOS does).
         */
 
-       if(SMB_VFS_STAT(conn,fname,&sb) != 0)
-               return -1;
-
        /* Check if we have write access. */
-       if (CAN_WRITE(conn)) {
-               if (((sb.st_mode & S_IWOTH) || conn->admin_user ||
-                       ((sb.st_mode & S_IWUSR) && current_user.uid==sb.st_uid) ||
-                       ((sb.st_mode & S_IWGRP) &&
-                               in_group(sb.st_gid,current_user.gid,
-                                       current_user.ngroups,current_user.groups)))) {
-                       /* We are allowed to become root and change the filetime. */
-                       become_root();
-                       ret = SMB_VFS_UTIME(conn,fname, times);
-                       unbecome_root();
-               }
+       if (can_write_to_file(conn, fname, &sbuf)) {
+               /* We are allowed to become root and change the filetime. */
+               become_root();
+               ret = SMB_VFS_UTIME(conn,fname, times);
+               unbecome_root();
        }
 
        return ret;
@@ -480,7 +481,7 @@ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times)
  Change a filetime - possibly allowing DOS semantics.
 *******************************************************************/
 
-BOOL set_filetime(connection_struct *conn, char *fname, time_t mtime)
+BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime)
 {
        struct utimbuf times;