/**************************************************************************** change a unix mode to a dos mode ****************************************************************************/ int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf) { int result = 0; DEBUG(8,("dos_mode: %s\n", path)); if ((sbuf->st_mode & S_IWUSR) == 0) result |= aRONLY; if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0)) result |= aARCH; if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0)) result |= aSYSTEM; if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0)) result |= aHIDDEN; if (S_ISDIR(sbuf->st_mode)) result = aDIR | (result & aRONLY); #ifdef S_ISLNK #if LINKS_READ_ONLY if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode)) result |= aRONLY; #endif #endif /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { char *p = strrchr(path,'/'); if (p) p++; else p = path; if (p[0] == '.' && p[1] != '.' && p[1] != 0) result |= aHIDDEN; } /* Optimization : Only call is_hidden_path if it's not already hidden. */ if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) { result |= aHIDDEN; } DEBUG(8,("dos_mode returning ")); if (result & aHIDDEN) DEBUG(8, ("h")); if (result & aRONLY ) DEBUG(8, ("r")); if (result & aSYSTEM) DEBUG(8, ("s")); if (result & aDIR ) DEBUG(8, ("d")); if (result & aARCH ) DEBUG(8, ("a")); DEBUG(8,("\n")); return(result); }
uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) { uint32 result = 0; DEBUG(8,("dos_mode: %s\n", path)); if (!VALID_STAT(*sbuf)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { const char *p = strrchr_m(path,'/'); if (p) { p++; } else { p = path; } if (p[0] == '.' && p[1] != '.' && p[1] != 0) { result |= aHIDDEN; } } /* Get the DOS attributes from an EA by preference. */ if (get_ea_dos_attribute(conn, path, sbuf, &result)) { result |= set_sparse_flag(sbuf); } else { result |= dos_mode_from_sbuf(conn, path, sbuf); } if (S_ISREG(sbuf->st_mode)) { result |= set_offline_flag(conn, path); } /* Optimization : Only call is_hidden_path if it's not already hidden. */ if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) { result |= aHIDDEN; } DEBUG(8,("dos_mode returning ")); if (result & aHIDDEN) DEBUG(8, ("h")); if (result & aRONLY ) DEBUG(8, ("r")); if (result & aSYSTEM) DEBUG(8, ("s")); if (result & aDIR ) DEBUG(8, ("d")); if (result & aARCH ) DEBUG(8, ("a")); if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]")); DEBUG(8,("\n")); return(result); }
uint32_t dos_mode_msdfs(connection_struct *conn, const struct smb_filename *smb_fname) { uint32_t result = 0; DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname))); if (!VALID_STAT(smb_fname->st)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { const char *p = strrchr_m(smb_fname->base_name, '/'); if (p) { p++; } else { p = smb_fname->base_name; } /* Only . and .. are not hidden. */ if (p[0] == '.' && !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0'))) { result |= FILE_ATTRIBUTE_HIDDEN; } } result |= dos_mode_from_sbuf(conn, smb_fname); /* Optimization : Only call is_hidden_path if it's not already hidden. */ if (!(result & FILE_ATTRIBUTE_HIDDEN) && IS_HIDDEN_PATH(conn, smb_fname->base_name)) { result |= FILE_ATTRIBUTE_HIDDEN; } if (result == 0) { result = FILE_ATTRIBUTE_NORMAL; } result = filter_mode_by_protocol(result); /* * Add in that it is a reparse point */ result |= FILE_ATTRIBUTE_REPARSE_POINT; dos_mode_debug_print(__func__, result); return(result); }
uint32 dos_mode(connection_struct *conn, struct smb_filename *smb_fname) { uint32 result = 0; bool offline; DEBUG(8,("dos_mode: %s\n", smb_fname_str_dbg(smb_fname))); if (!VALID_STAT(smb_fname->st)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { const char *p = strrchr_m(smb_fname->base_name,'/'); if (p) { p++; } else { p = smb_fname->base_name; } /* Only . and .. are not hidden. */ if (p[0] == '.' && !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0'))) { result |= FILE_ATTRIBUTE_HIDDEN; } } /* Get the DOS attributes from an EA by preference. */ if (!get_ea_dos_attribute(conn, smb_fname, &result)) { result |= dos_mode_from_sbuf(conn, smb_fname); } offline = SMB_VFS_IS_OFFLINE(conn, smb_fname, &smb_fname->st); if (S_ISREG(smb_fname->st.st_ex_mode) && offline) { result |= FILE_ATTRIBUTE_OFFLINE; } if (conn->fs_capabilities & FILE_FILE_COMPRESSION) { bool compressed = false; NTSTATUS status = dos_mode_check_compressed(conn, smb_fname, &compressed); if (NT_STATUS_IS_OK(status) && compressed) { result |= FILE_ATTRIBUTE_COMPRESSED; } } /* Optimization : Only call is_hidden_path if it's not already hidden. */ if (!(result & FILE_ATTRIBUTE_HIDDEN) && IS_HIDDEN_PATH(conn, smb_fname->base_name)) { result |= FILE_ATTRIBUTE_HIDDEN; } if (result == 0) { result = FILE_ATTRIBUTE_NORMAL; } result = filter_mode_by_protocol(result); dos_mode_debug_print(result); return result; }
static bool get_ea_dos_attribute(connection_struct *conn, struct smb_filename *smb_fname, uint32 *pattr) { struct xattr_DOSATTRIB dosattrib; enum ndr_err_code ndr_err; DATA_BLOB blob; ssize_t sizeret; fstring attrstr; uint32_t dosattr; if (!lp_store_dos_attributes(SNUM(conn))) { return False; } /* Don't reset pattr to zero as we may already have filename-based attributes we need to preserve. */ sizeret = SMB_VFS_GETXATTR(conn, smb_fname->base_name, SAMBA_XATTR_DOS_ATTRIB, attrstr, sizeof(attrstr)); if (sizeret == -1) { if (errno == ENOSYS #if defined(ENOTSUP) || errno == ENOTSUP) { #else ) { #endif DEBUG(1,("get_ea_dos_attribute: Cannot get attribute " "from EA on file %s: Error = %s\n", smb_fname_str_dbg(smb_fname), strerror(errno))); set_store_dos_attributes(SNUM(conn), False); } return False; } blob.data = (uint8_t *)attrstr; blob.length = sizeret; ndr_err = ndr_pull_struct_blob(&blob, talloc_tos(), &dosattrib, (ndr_pull_flags_fn_t)ndr_pull_xattr_DOSATTRIB); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(1,("get_ea_dos_attribute: bad ndr decode " "from EA on file %s: Error = %s\n", smb_fname_str_dbg(smb_fname), ndr_errstr(ndr_err))); return false; } DEBUG(10,("get_ea_dos_attribute: %s attr = %s\n", smb_fname_str_dbg(smb_fname), dosattrib.attrib_hex)); switch (dosattrib.version) { case 0xFFFF: dosattr = dosattrib.info.compatinfoFFFF.attrib; break; case 1: dosattr = dosattrib.info.info1.attrib; if (!null_nttime(dosattrib.info.info1.create_time)) { struct timespec create_time = nt_time_to_unix_timespec( dosattrib.info.info1.create_time); update_stat_ex_create_time(&smb_fname->st, create_time); DEBUG(10,("get_ea_dos_attribute: file %s case 1 " "set btime %s\n", smb_fname_str_dbg(smb_fname), time_to_asc(convert_timespec_to_time_t( create_time)) )); } break; case 2: dosattr = dosattrib.info.oldinfo2.attrib; /* Don't know what flags to check for this case. */ break; case 3: dosattr = dosattrib.info.info3.attrib; if ((dosattrib.info.info3.valid_flags & XATTR_DOSINFO_CREATE_TIME) && !null_nttime(dosattrib.info.info3.create_time)) { struct timespec create_time = nt_time_to_unix_timespec( dosattrib.info.info3.create_time); update_stat_ex_create_time(&smb_fname->st, create_time); DEBUG(10,("get_ea_dos_attribute: file %s case 3 " "set btime %s\n", smb_fname_str_dbg(smb_fname), time_to_asc(convert_timespec_to_time_t( create_time)) )); } break; default: DEBUG(1,("get_ea_dos_attribute: Badly formed DOSATTRIB on " "file %s - %s\n", smb_fname_str_dbg(smb_fname), attrstr)); return false; } if (S_ISDIR(smb_fname->st.st_ex_mode)) { dosattr |= FILE_ATTRIBUTE_DIRECTORY; } /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */ *pattr = (uint32)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE)); DEBUG(8,("get_ea_dos_attribute returning (0x%x)", dosattr)); if (dosattr & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h")); if (dosattr & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r")); if (dosattr & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s")); if (dosattr & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d")); if (dosattr & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a")); DEBUG(8,("\n")); return True; } /**************************************************************************** Set DOS attributes in an EA. Also sets the create time. ****************************************************************************/ static bool set_ea_dos_attribute(connection_struct *conn, struct smb_filename *smb_fname, uint32 dosmode) { struct xattr_DOSATTRIB dosattrib; enum ndr_err_code ndr_err; DATA_BLOB blob; ZERO_STRUCT(dosattrib); ZERO_STRUCT(blob); dosattrib.version = 3; dosattrib.info.info3.valid_flags = XATTR_DOSINFO_ATTRIB| XATTR_DOSINFO_CREATE_TIME; dosattrib.info.info3.attrib = dosmode; dosattrib.info.info3.create_time = unix_timespec_to_nt_time( smb_fname->st.st_ex_btime); DEBUG(10,("set_ea_dos_attributes: set attribute 0x%x, btime = %s on file %s\n", (unsigned int)dosmode, time_to_asc(convert_timespec_to_time_t(smb_fname->st.st_ex_btime)), smb_fname_str_dbg(smb_fname) )); ndr_err = ndr_push_struct_blob( &blob, talloc_tos(), &dosattrib, (ndr_push_flags_fn_t)ndr_push_xattr_DOSATTRIB); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { DEBUG(5, ("create_acl_blob: ndr_push_xattr_DOSATTRIB failed: %s\n", ndr_errstr(ndr_err))); return false; } if (blob.data == NULL || blob.length == 0) { return false; } if (SMB_VFS_SETXATTR(conn, smb_fname->base_name, SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length, 0) == -1) { bool ret = false; bool need_close = false; files_struct *fsp = NULL; if((errno != EPERM) && (errno != EACCES)) { if (errno == ENOSYS #if defined(ENOTSUP) || errno == ENOTSUP) { #else ) { #endif DEBUG(1,("set_ea_dos_attributes: Cannot set " "attribute EA on file %s: Error = %s\n", smb_fname_str_dbg(smb_fname), strerror(errno) )); set_store_dos_attributes(SNUM(conn), False); } return false; } /* We want DOS semantics, ie allow non owner with write permission to change the bits on a file. Just like file_ntimes below. */ /* Check if we have write access. */ if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) return false; if (!can_write_to_file(conn, smb_fname)) { return false; } /* * We need to get an open file handle to do the * metadata operation under root. */ if (!NT_STATUS_IS_OK(get_file_handle_for_metadata(conn, smb_fname, &fsp, &need_close))) { return false; } become_root(); if (SMB_VFS_FSETXATTR(fsp, SAMBA_XATTR_DOS_ATTRIB, blob.data, blob.length, 0) == 0) { ret = true; } unbecome_root(); if (need_close) { close_file(NULL, fsp, NORMAL_CLOSE); } return ret; } DEBUG(10,("set_ea_dos_attribute: set EA 0x%x on file %s\n", (unsigned int)dosmode, smb_fname_str_dbg(smb_fname))); return true; } /**************************************************************************** Change a unix mode to a dos mode for an ms dfs link. ****************************************************************************/ uint32 dos_mode_msdfs(connection_struct *conn, const struct smb_filename *smb_fname) { uint32 result = 0; DEBUG(8,("dos_mode_msdfs: %s\n", smb_fname_str_dbg(smb_fname))); if (!VALID_STAT(smb_fname->st)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { const char *p = strrchr_m(smb_fname->base_name, '/'); if (p) { p++; } else { p = smb_fname->base_name; } /* Only . and .. are not hidden. */ if (p[0] == '.' && !((p[1] == '\0') || (p[1] == '.' && p[2] == '\0'))) { result |= FILE_ATTRIBUTE_HIDDEN; } } result |= dos_mode_from_sbuf(conn, smb_fname); /* Optimization : Only call is_hidden_path if it's not already hidden. */ if (!(result & FILE_ATTRIBUTE_HIDDEN) && IS_HIDDEN_PATH(conn, smb_fname->base_name)) { result |= FILE_ATTRIBUTE_HIDDEN; } if (result == 0) { result = FILE_ATTRIBUTE_NORMAL; } result = filter_mode_by_protocol(result); /* * Add in that it is a reparse point */ result |= FILE_ATTRIBUTE_REPARSE_POINT; DEBUG(8,("dos_mode_msdfs returning ")); if (result & FILE_ATTRIBUTE_HIDDEN) DEBUG(8, ("h")); if (result & FILE_ATTRIBUTE_READONLY ) DEBUG(8, ("r")); if (result & FILE_ATTRIBUTE_SYSTEM) DEBUG(8, ("s")); if (result & FILE_ATTRIBUTE_DIRECTORY ) DEBUG(8, ("d")); if (result & FILE_ATTRIBUTE_ARCHIVE ) DEBUG(8, ("a")); if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]")); DEBUG(8,("\n")); return(result); }
static BOOL set_ea_dos_attribute(connection_struct *conn, const char *path, SMB_STRUCT_STAT *sbuf, uint32 dosmode) { fstring attrstr; files_struct *fsp = NULL; BOOL ret = False; if (!lp_store_dos_attributes(SNUM(conn))) { return False; } snprintf(attrstr, sizeof(attrstr)-1, "0x%x", dosmode & SAMBA_ATTRIBUTES_MASK); if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == -1) { if((errno != EPERM) && (errno != EACCES)) { if (errno == ENOSYS #if defined(ENOTSUP) || errno == ENOTSUP) { #else ) { #endif set_store_dos_attributes(SNUM(conn), False); } return False; } /* We want DOS semantics, ie allow non owner with write permission to change the bits on a file. Just like file_ntimes below. */ /* Check if we have write access. */ if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn))) return False; /* * We need to open the file with write access whilst * still in our current user context. This ensures we * are not violating security in doing the setxattr. */ if (!NT_STATUS_IS_OK(open_file_fchmod(conn,path,sbuf,&fsp))) return ret; become_root(); if (SMB_VFS_SETXATTR(conn, path, SAMBA_XATTR_DOS_ATTRIB, attrstr, strlen(attrstr), 0) == 0) { ret = True; } unbecome_root(); close_file_fchmod(fsp); return ret; } DEBUG(10,("set_ea_dos_attribute: set EA %s on file %s\n", attrstr, path)); return True; } /**************************************************************************** Change a unix mode to a dos mode for an ms dfs link. ****************************************************************************/ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf) { uint32 result = 0; DEBUG(8,("dos_mode_msdfs: %s\n", path)); if (!VALID_STAT(*sbuf)) { return 0; } /* First do any modifications that depend on the path name. */ /* hide files with a name starting with a . */ if (lp_hide_dot_files(SNUM(conn))) { const char *p = strrchr_m(path,'/'); if (p) { p++; } else { p = path; } if (p[0] == '.' && p[1] != '.' && p[1] != 0) { result |= aHIDDEN; } } result |= dos_mode_from_sbuf(conn, path, sbuf); /* Optimization : Only call is_hidden_path if it's not already hidden. */ if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) { result |= aHIDDEN; } DEBUG(8,("dos_mode_msdfs returning ")); if (result & aHIDDEN) DEBUG(8, ("h")); if (result & aRONLY ) DEBUG(8, ("r")); if (result & aSYSTEM) DEBUG(8, ("s")); if (result & aDIR ) DEBUG(8, ("d")); if (result & aARCH ) DEBUG(8, ("a")); if (result & FILE_ATTRIBUTE_SPARSE ) DEBUG(8, ("[sparse]")); DEBUG(8,("\n")); return(result); }