1 /*
   2  * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "FileAttributes.h"
  27 
  28 #include <algorithm>
  29 #include <list>
  30 #include <sys/stat.h>
  31 
  32 FileAttributes::FileAttributes(const TString FileName, bool FollowLink) {
  33     FFileName = FileName;
  34     FFollowLink = FollowLink;
  35     ReadAttributes();
  36 }
  37 
  38 bool FileAttributes::WriteAttributes() {
  39     bool result = false;
  40 
  41     mode_t attributes = 0;
  42 
  43     for (std::vector<FileAttribute>::const_iterator iterator =
  44             FAttributes.begin();
  45             iterator != FAttributes.end(); iterator++) {
  46         switch (*iterator) {
  47             case faBlockSpecial:
  48             {
  49                 attributes |= S_IFBLK;
  50                 break;
  51             }
  52             case faCharacterSpecial:
  53             {
  54                 attributes |= S_IFCHR;
  55                 break;
  56             }
  57             case faFIFOSpecial:
  58             {
  59                 attributes |= S_IFIFO;
  60                 break;
  61             }
  62             case faNormal:
  63             {
  64                 attributes |= S_IFREG;
  65                 break;
  66             }
  67             case faDirectory:
  68             {
  69                 attributes |= S_IFDIR;
  70                 break;
  71             }
  72             case faSymbolicLink:
  73             {
  74                 attributes |= S_IFLNK;
  75                 break;
  76             }
  77             case faSocket:
  78             {
  79                 attributes |= S_IFSOCK;
  80                 break;
  81             }
  82 
  83                 // Owner
  84             case faReadOnly:
  85             {
  86                 attributes |= S_IRUSR;
  87                 break;
  88             }
  89             case faWriteOnly:
  90             {
  91                 attributes |= S_IWUSR;
  92                 break;
  93             }
  94             case faReadWrite:
  95             {
  96                 attributes |= S_IRUSR;
  97                 attributes |= S_IWUSR;
  98                 break;
  99             }
 100             case faExecute:
 101             {
 102                 attributes |= S_IXUSR;
 103                 break;
 104             }
 105 
 106                 // Group
 107             case faGroupReadOnly:
 108             {
 109                 attributes |= S_IRGRP;
 110                 break;
 111             }
 112             case faGroupWriteOnly:
 113             {
 114                 attributes |= S_IWGRP;
 115                 break;
 116             }
 117             case faGroupReadWrite:
 118             {
 119                 attributes |= S_IRGRP;
 120                 attributes |= S_IWGRP;
 121                 break;
 122             }
 123             case faGroupExecute:
 124             {
 125                 attributes |= S_IXGRP;
 126                 break;
 127             }
 128 
 129                 // Others
 130             case faOthersReadOnly:
 131             {
 132                 attributes |= S_IROTH;
 133                 break;
 134             }
 135             case faOthersWriteOnly:
 136             {
 137                 attributes |= S_IWOTH;
 138                 break;
 139             }
 140             case faOthersReadWrite:
 141             {
 142                 attributes |= S_IROTH;
 143                 attributes |= S_IWOTH;
 144                 break;
 145             }
 146             case faOthersExecute:
 147             {
 148                 attributes |= S_IXOTH;
 149                 break;
 150             }
 151             default:
 152                 break;
 153         }
 154     }
 155 
 156     if (chmod(FFileName.data(), attributes) == 0) {
 157         result = true;
 158     }
 159 
 160     return result;
 161 }
 162 
 163 #define S_ISRUSR(m)    (((m) & S_IRWXU) == S_IRUSR)
 164 #define S_ISWUSR(m)    (((m) & S_IRWXU) == S_IWUSR)
 165 #define S_ISXUSR(m)    (((m) & S_IRWXU) == S_IXUSR)
 166 
 167 #define S_ISRGRP(m)    (((m) & S_IRWXG) == S_IRGRP)
 168 #define S_ISWGRP(m)    (((m) & S_IRWXG) == S_IWGRP)
 169 #define S_ISXGRP(m)    (((m) & S_IRWXG) == S_IXGRP)
 170 
 171 #define S_ISROTH(m)    (((m) & S_IRWXO) == S_IROTH)
 172 #define S_ISWOTH(m)    (((m) & S_IRWXO) == S_IWOTH)
 173 #define S_ISXOTH(m)    (((m) & S_IRWXO) == S_IXOTH)
 174 
 175 bool FileAttributes::ReadAttributes() {
 176     bool result = false;
 177 
 178     struct stat status;
 179 
 180     if (stat(StringToFileSystemString(FFileName), &status) == 0) {
 181         result = true;
 182 
 183         if (S_ISBLK(status.st_mode) != 0) {
 184             FAttributes.push_back(faBlockSpecial);
 185         }
 186         if (S_ISCHR(status.st_mode) != 0) {
 187             FAttributes.push_back(faCharacterSpecial);
 188         }
 189         if (S_ISFIFO(status.st_mode) != 0) {
 190             FAttributes.push_back(faFIFOSpecial);
 191         }
 192         if (S_ISREG(status.st_mode) != 0) {
 193             FAttributes.push_back(faNormal);
 194         }
 195         if (S_ISDIR(status.st_mode) != 0) {
 196             FAttributes.push_back(faDirectory);
 197         }
 198         if (S_ISLNK(status.st_mode) != 0) {
 199             FAttributes.push_back(faSymbolicLink);
 200         }
 201         if (S_ISSOCK(status.st_mode) != 0) {
 202             FAttributes.push_back(faSocket);
 203         }
 204 
 205         // Owner
 206         if (S_ISRUSR(status.st_mode) != 0) {
 207             if (S_ISWUSR(status.st_mode) != 0) {
 208                 FAttributes.push_back(faReadWrite);
 209             } else {
 210                 FAttributes.push_back(faReadOnly);
 211             }
 212         } else if (S_ISWUSR(status.st_mode) != 0) {
 213             FAttributes.push_back(faWriteOnly);
 214         }
 215 
 216         if (S_ISXUSR(status.st_mode) != 0) {
 217             FAttributes.push_back(faExecute);
 218         }
 219 
 220         // Group
 221         if (S_ISRGRP(status.st_mode) != 0) {
 222             if (S_ISWGRP(status.st_mode) != 0) {
 223                 FAttributes.push_back(faGroupReadWrite);
 224             } else {
 225                 FAttributes.push_back(faGroupReadOnly);
 226             }
 227         } else if (S_ISWGRP(status.st_mode) != 0) {
 228             FAttributes.push_back(faGroupWriteOnly);
 229         }
 230 
 231         if (S_ISXGRP(status.st_mode) != 0) {
 232             FAttributes.push_back(faGroupExecute);
 233         }
 234 
 235 
 236         // Others
 237         if (S_ISROTH(status.st_mode) != 0) {
 238             if (S_ISWOTH(status.st_mode) != 0) {
 239                 FAttributes.push_back(faOthersReadWrite);
 240             } else {
 241                 FAttributes.push_back(faOthersReadOnly);
 242             }
 243         } else if (S_ISWOTH(status.st_mode) != 0) {
 244             FAttributes.push_back(faOthersWriteOnly);
 245         }
 246 
 247         if (S_ISXOTH(status.st_mode) != 0) {
 248             FAttributes.push_back(faOthersExecute);
 249         }
 250 
 251         if (FFileName.size() > 0 && FFileName[0] == '.') {
 252             FAttributes.push_back(faHidden);
 253         }
 254     }
 255 
 256     return result;
 257 }
 258 
 259 bool FileAttributes::Valid(const FileAttribute Value) {
 260     bool result = false;
 261 
 262     switch (Value) {
 263         case faReadWrite:
 264         case faWriteOnly:
 265         case faExecute:
 266 
 267         case faGroupReadWrite:
 268         case faGroupWriteOnly:
 269         case faGroupReadOnly:
 270         case faGroupExecute:
 271 
 272         case faOthersReadWrite:
 273         case faOthersWriteOnly:
 274         case faOthersReadOnly:
 275         case faOthersExecute:
 276 
 277         case faReadOnly:
 278             result = true;
 279             break;
 280 
 281         default:
 282             break;
 283     }
 284 
 285     return result;
 286 }
 287 
 288 void FileAttributes::Append(FileAttribute Value) {
 289     if (Valid(Value) == true) {
 290         if ((Value == faReadOnly && Contains(faWriteOnly) == true) ||
 291                 (Value == faWriteOnly && Contains(faReadOnly) == true)) {
 292             Value = faReadWrite;
 293         }
 294 
 295         FAttributes.push_back(Value);
 296         WriteAttributes();
 297     }
 298 }
 299 
 300 bool FileAttributes::Contains(FileAttribute Value) {
 301     bool result = false;
 302 
 303     std::vector<FileAttribute>::const_iterator iterator =
 304             std::find(FAttributes.begin(), FAttributes.end(), Value);
 305 
 306     if (iterator != FAttributes.end()) {
 307         result = true;
 308     }
 309 
 310     return result;
 311 }
 312 
 313 void FileAttributes::Remove(FileAttribute Value) {
 314     if (Valid(Value) == true) {
 315         if (Value == faReadOnly && Contains(faReadWrite) == true) {
 316             Append(faWriteOnly);
 317             Remove(faReadWrite);
 318         } else if (Value == faWriteOnly && Contains(faReadWrite) == true) {
 319             Append(faReadOnly);
 320             Remove(faReadWrite);
 321         }
 322 
 323         std::vector<FileAttribute>::iterator iterator =
 324                 std::find(FAttributes.begin(), FAttributes.end(), Value);
 325 
 326         if (iterator != FAttributes.end()) {
 327             FAttributes.erase(iterator);
 328             WriteAttributes();
 329         }
 330     }
 331 }