/******************************************************************* chmod a file - but preserve some bits ********************************************************************/ int file_chmod(connection_struct *conn,char *fname,int dosmode,SMB_STRUCT_STAT *st) { SMB_STRUCT_STAT st1; int mask=0; mode_t tmp; mode_t unixmode; if (!st) { st = &st1; if (dos_stat(fname,st)) return(-1); } if (S_ISDIR(st->st_mode)) dosmode |= aDIR; if (dos_mode(conn,fname,st) == dosmode) return(0); unixmode = unix_mode(conn,dosmode,fname); /* preserve the s bits */ mask |= (S_ISUID | S_ISGID); /* preserve the t bit */ #ifdef S_ISVTX mask |= S_ISVTX; #endif /* possibly preserve the x bits */ if (!MAP_ARCHIVE(conn)) mask |= S_IXUSR; if (!MAP_SYSTEM(conn)) mask |= S_IXGRP; if (!MAP_HIDDEN(conn)) mask |= S_IXOTH; unixmode |= (st->st_mode & mask); /* if we previously had any r bits set then leave them alone */ if ((tmp = st->st_mode & (S_IRUSR|S_IRGRP|S_IROTH))) { unixmode &= ~(S_IRUSR|S_IRGRP|S_IROTH); unixmode |= tmp; } /* if we previously had any w bits set then leave them alone whilst adding in the new w bits, if the new mode is not rdonly */ if (!IS_DOS_READONLY(dosmode)) { unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); } return(dos_chmod(fname,unixmode)); }
/******************************************************************* Wrapper around dos_utime that possibly allows DOS semantics rather than POSIX. *******************************************************************/ int file_utime(connection_struct *conn, char *fname, struct utimbuf *times) { extern struct current_user current_user; SMB_STRUCT_STAT sb; int ret = -1; errno = 0; if(dos_utime(fname, times) == 0) return 0; if((errno != EPERM) && (errno != EACCES)) return -1; if(!lp_dos_filetimes(SNUM(conn))) return -1; /* We have permission (given by the Samba admin) to break POSIX semantics and allow a user to change the time on a file they don't own but can write to (as DOS does). */ if(dos_stat(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(False); ret = dos_utime(fname, times); unbecome_root(False); } } return ret; }
char *dos_GetWd(char *path) { pstring s; static BOOL getwd_cache_init = False; SMB_STRUCT_STAT st, st2; int i; *s = 0; if (!use_getwd_cache) return(dos_getwd(path)); /* init the cache */ if (!getwd_cache_init) { getwd_cache_init = True; for (i=0;i<MAX_GETWDCACHE;i++) { string_set(&ino_list[i].dos_path,""); ino_list[i].valid = False; } } /* Get the inode of the current directory, if this doesn't work we're in trouble :-) */ if (sys_stat(".",&st) == -1) { DEBUG(0,("Very strange, couldn't stat \".\" path=%s\n", path)); return(dos_getwd(path)); } for (i=0; i<MAX_GETWDCACHE; i++) if (ino_list[i].valid) { /* If we have found an entry with a matching inode and dev number then find the inode number for the directory in the cached string. If this agrees with that returned by the stat for the current directory then all is o.k. (but make sure it is a directory all the same...) */ if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) { if (dos_stat(ino_list[i].dos_path,&st2) == 0) { if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev && (st2.st_mode & S_IFMT) == S_IFDIR) { pstrcpy (path, ino_list[i].dos_path); /* promote it for future use */ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); return (path); } else { /* If the inode is different then something's changed, scrub the entry and start from scratch. */ ino_list[i].valid = False; } } } } /* We don't have the information to hand so rely on traditional methods. The very slow getcwd, which spawns a process on some systems, or the not quite so bad getwd. */ if (!dos_getwd(s)) { DEBUG(0,("dos_GetWd: dos_getwd call failed, errno %s\n",strerror(errno))); return (NULL); } pstrcpy(path,s); DEBUG(5,("dos_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev)); /* add it to the cache */ i = MAX_GETWDCACHE - 1; string_set(&ino_list[i].dos_path,s); ino_list[i].dev = st.st_dev; ino_list[i].inode = st.st_ino; ino_list[i].valid = True; /* put it at the top of the list */ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); return (path); }
/**************************************************************************** change a dos mode to a unix mode base permission for files: if inheriting apply read/write bits from parent directory. else everybody gets read bit set dos readonly is represented in unix by removing everyone's write bit dos archive is represented in unix by the user's execute bit dos system is represented in unix by the group's execute bit dos hidden is represented in unix by the other's execute bit if !inheriting { Then apply create mask, then add force bits. } base permission for directories: dos directory is represented in unix by unix's dir bit and the exec bit if !inheriting { Then apply create mask, then add force bits. } ****************************************************************************/ mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname) { mode_t result = (S_IRUSR | S_IRGRP | S_IROTH); mode_t dir_mode = 0; /* Mode of the parent directory if inheriting. */ if ( !IS_DOS_READONLY(dosmode) ) result |= (S_IWUSR | S_IWGRP | S_IWOTH); if (fname && lp_inherit_perms(SNUM(conn))) { char *dname; SMB_STRUCT_STAT sbuf; dname = parent_dirname(fname); DEBUG(2,("unix_mode(%s) inheriting from %s\n",fname,dname)); if (dos_stat(dname,&sbuf) != 0) { DEBUG(4,("unix_mode(%s) failed, [dir %s]: %s\n",fname,dname,strerror(errno))); return(0); /* *** shouldn't happen! *** */ } /* Save for later - but explicitly remove setuid bit for safety. */ dir_mode = sbuf.st_mode & ~S_ISUID; DEBUG(2,("unix_mode(%s) inherit mode %o\n",fname,(int)dir_mode)); /* Clear "result" */ result = 0; } if (IS_DOS_DIR(dosmode)) { /* We never make directories read only for the owner as under DOS a user can always create a file in a read-only directory. */ result |= (S_IFDIR | S_IWUSR); if (dir_mode) { /* Inherit mode of parent directory. */ result |= dir_mode; } else { /* Provisionally add all 'x' bits */ result |= (S_IXUSR | S_IXGRP | S_IXOTH); /* Apply directory mask */ result &= lp_dir_mask(SNUM(conn)); /* Add in force bits */ result |= lp_force_dir_mode(SNUM(conn)); } } else { if (lp_map_archive(SNUM(conn)) && IS_DOS_ARCHIVE(dosmode)) result |= S_IXUSR; if (lp_map_system(SNUM(conn)) && IS_DOS_SYSTEM(dosmode)) result |= S_IXGRP; if (lp_map_hidden(SNUM(conn)) && IS_DOS_HIDDEN(dosmode)) result |= S_IXOTH; if (dir_mode) { /* Inherit 666 component of parent directory mode */ result |= dir_mode & (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP | S_IWOTH); } else { /* Apply mode mask */ result &= lp_create_mask(SNUM(conn)); /* Add in force bits */ result |= lp_force_create_mode(SNUM(conn)); } } return(result); }
/* **************************************************************** * Remove um arquivo * **************************************************************** */ void simple_rm (const char *path) { DOSSTAT z; /* * Obtém o estado do arquivo */ if (dos_stat (path, &z) < 0) { printf ( "%s: Não consegui obter o estado de \"%s\" (%s)\n", cmd_nm, path, strerror (errno) ); return; } #undef DEBUG #ifdef DEBUG printf ( "simple_rm: entries = %d, clusno = %d\n", z.z_lfn_entries, z.z_lfn_clusno ); printf ( "simple_rm: blkno = %d, end_blkno = %d, offset = %d\n", z.z_lfn_blkno, z.z_lfn_end_blkno, z.z_lfn_offset ); #endif DEBUG /* * Se necessário, pede confirmação do usuario */ if (cmd_iflag) { fprintf ( stderr, "(%c, %d) %s? (n): ", file_type_edit (z.z_mode), GET_LONG (z.z_size), path ); if (askyesno () <= 0) return; } elif (cmd_vflag) { printf ("%s:\n", path); } /* * Verifica se é um arquivo regular */ if (Z_ISDIR (z.z_mode)) { printf ( "%s: O arquivo \"%s\" é um diretório\n", cmd_nm, path ); return; } /* * Verifica se tem o bit "r" ligado */ if (z.z_mode & Z_RO) { fprintf ( stderr, "%s: O arquivo \"%s\" só permite leituras - " "remove? (n): ", cmd_nm, path ); if (askyesno () <= 0) return; } /* * Remove o arquivo */ if (dos_unlink (&z, 1 /* trunca */) < 0) return; /* * Verifica se alterou o nome do volume principal */ if (Z_ISVOL (z.z_mode)) { vol_nm[0] = '\0'; dir_walk (vol_search, uni.u_root_cluster); } } /* end simple_rm */