1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/image_aggregator/sparse_image_utils.h"
18 
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <string.h>
22 #include <sys/file.h>
23 
24 #include <fstream>
25 
26 #include "common/libs/fs/shared_fd.h"
27 #include "common/libs/fs/shared_select.h"
28 #include "common/libs/utils/subprocess.h"
29 #include "host/libs/config/cuttlefish_config.h"
30 
31 
32 const char ANDROID_SPARSE_IMAGE_MAGIC[] = "\x3A\xFF\x26\xED";
33 namespace cuttlefish {
34 
ReleaseLock(const SharedFD & fd,const std::string & tmp_lock_image_path)35 void ReleaseLock(const SharedFD& fd,
36                  const std::string& tmp_lock_image_path) {
37   auto funlock_result = fd->Flock(LOCK_UN | LOCK_NB);
38   fd->Close();
39   if (!funlock_result.ok()) {
40     LOG(FATAL) << "It failed to unlock file " << tmp_lock_image_path;
41   }
42 }
43 
AcquireLock(SharedFD & fd,const std::string & tmp_lock_image_path)44 bool AcquireLock(SharedFD& fd, const std::string& tmp_lock_image_path) {
45   fd = SharedFD::Open(tmp_lock_image_path.c_str(),
46                         O_RDWR | O_CREAT, 0666);
47   if (!fd->IsOpen()) {
48     LOG(FATAL) << tmp_lock_image_path << " file open failed";
49     return false;
50   }
51   auto flock_result = fd->Flock(LOCK_EX);
52   if (!flock_result.ok()) {
53     LOG(FATAL) << "flock failed";
54     return false;
55   }
56   return true;
57 }
58 
IsSparseImage(const std::string & image_path)59 bool IsSparseImage(const std::string& image_path) {
60   std::ifstream file(image_path, std::ios::binary);
61   if (!file) {
62     LOG(FATAL) << "Could not open '" << image_path << "'";
63     return false;
64   }
65   char buffer[5] = {0};
66   file.read(buffer, 4);
67   file.close();
68   return strcmp(ANDROID_SPARSE_IMAGE_MAGIC, buffer) == 0;
69 }
70 
ConvertToRawImage(const std::string & image_path)71 bool ConvertToRawImage(const std::string& image_path) {
72   SharedFD fd;
73   std::string tmp_lock_image_path = image_path + ".lock";
74 
75   if(AcquireLock(fd, tmp_lock_image_path) == false) {
76     return false;
77   }
78 
79   if (!IsSparseImage(image_path)) {
80     // Release lock before return
81     LOG(DEBUG) << "Skip non-sparse image " << image_path;
82     return false;
83   }
84 
85   auto simg2img_path = HostBinaryPath("simg2img");
86   Command simg2img_cmd(simg2img_path);
87   std::string tmp_raw_image_path = image_path + ".raw";
88   simg2img_cmd.AddParameter(image_path);
89   simg2img_cmd.AddParameter(tmp_raw_image_path);
90 
91   // Use simg2img to convert sparse image to raw image.
92   int success = simg2img_cmd.Start().Wait();
93   if (success != 0) {
94     // Release lock before FATAL and return
95     LOG(FATAL) << "Unable to convert Android sparse image " << image_path
96                << " to raw image. " << success;
97     return false;
98   }
99 
100   // Replace the original sparse image with the raw image.
101   if (unlink(image_path.c_str()) != 0) {
102     // Release lock before FATAL and return
103     PLOG(FATAL) << "Unable to delete original sparse image";
104   }
105 
106   Command mv_cmd("/bin/mv");
107   mv_cmd.AddParameter("-f");
108   mv_cmd.AddParameter(tmp_raw_image_path);
109   mv_cmd.AddParameter(image_path);
110   success = mv_cmd.Start().Wait();
111   // Release lock and leave critical section
112   ReleaseLock(fd, tmp_lock_image_path);
113   if (success != 0) {
114     LOG(FATAL) << "Unable to rename raw image " << success;
115     return false;
116   }
117 
118   return true;
119 }
120 
121 }  // namespace cuttlefish
122