lin
2025-03-11 6f4f7a76e03a46fefb056a4b18197f1d9e8aa939
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include <ctype.h>
#include <errno.h>
#include <ftw.h>
#include <libgen.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
 
#include "android-base/logging.h"
 
// The name of the directory that holds a staged time zone update distro. If this exists it should
// replace the one in CURRENT_DIR_NAME.
// See also com.android.timezone.distro.installer.TimeZoneDistroInstaller.
static const char* STAGED_DIR_NAME = "/staged";
 
// The name of the directory that holds the (optional) installed time zone update distro.
// See also com.android.timezone.distro.installer.TimeZoneDistroInstaller.
static const char* CURRENT_DIR_NAME = "/current";
 
// The name of a file in the staged dir that indicates the staged operation is an "uninstall".
// See also com.android.timezone.distro.installer.TimeZoneDistroInstaller.
static const char* UNINSTALL_TOMBSTONE_FILE_NAME = "/STAGED_UNINSTALL_TOMBSTONE";
 
// The name of the file containing the distro version information.
// See also com.android.timezone.distro.TimeZoneDistro / com.android.timezone.distro.DistroVersion.
static const char* DISTRO_VERSION_FILENAME = "/distro_version";
 
// The name of the file containing the base tz data set version information.
// See also libcore.timezone.TzDataSetVersion.
static const char* BASE_VERSION_FILENAME = "/tz_version";
 
// distro_version / tz_version are ASCII files consisting of at least 17 bytes in the
// form: AAA.BBB|CCCCC|DDD
// AAA.BBB is the major/minor version of the format (e.g. 004.001),
// CCCCC is the rules version (e.g. 2016g),
// DDD is the android revision for this rules version to allow for data corrections (e.g. 001),
// We only use the first 13 to determine suitability of format / data.
static const int READ_DATA_LENGTH = 13;
 
// Version bytes are: AAA.BBB|CCCCC - the format version is AAA.BBB
// The length of the format version,  e.g. "004.001" == 7 bytes
static const size_t FORMAT_VERSION_LEN = 7;
 
// Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
static const size_t FORMAT_MAJOR_VERSION_LEN = 3;
 
// Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
static const size_t FORMAT_MAJOR_VERSION_IDX = 0;
 
// Version bytes are: AAA.BBB|CCCCC - the format major version is AAA
static const size_t FORMAT_MINOR_VERSION_LEN = 3;
 
// Version bytes are: AAA.BBB|CCCCC - the format minor version is BBB
static const size_t FORMAT_MINOR_VERSION_IDX = 4;
 
// Version bytes are: AAA.BBB|CCCCC - the IANA rules version is CCCCC
// The length of the IANA rules version bytes, e.g. 2016a
static const size_t RULES_VERSION_LEN = 5;
 
// Version bytes are: AAA.BBB|CCCCC - the rules version is CCCCC
static const size_t VERSION_RULES_IDX = 8;
 
 
static void usage() {
    std::cerr << "Usage: tzdatacheck BASE_TZ_DIR DATA_TZ_DIR\n"
            "\n"
            "Checks whether any timezone update distro in DATA_TZ_DIR is compatible with the\n"
            "current Android release and better than or the same as base timezone rules in\n"
            "BASE_TZ_DIR. If the timezone rules in BASE_TZ_DIR are a higher version than the\n"
            "one in DATA_TZ_DIR the DATA_TZ_DIR is renamed and then deleted.\n";
    exit(1);
}
 
/*
 * Opens a file and fills buffer with the first byteCount bytes from the file.
 * If the file does not exist or cannot be opened or is too short then false is returned.
 * If the bytes were read successfully then true is returned.
 */
static bool readBytes(const std::string& fileName, char* buffer, size_t byteCount) {
    FILE* file = fopen(fileName.c_str(), "r");
    if (file == nullptr) {
        if (errno != ENOENT) {
            PLOG(WARNING) << "Error opening file " << fileName;
        }
        return false;
    }
    size_t bytesRead = fread(buffer, 1, byteCount, file);
    fclose(file);
    if (bytesRead != byteCount) {
        LOG(WARNING) << fileName << " is too small. " << byteCount << " bytes required";
        return false;
    }
    return true;
}
 
static bool checkDigits(const char* buffer, const size_t count, size_t* i) {
    for (size_t j = 0; j < count; j++) {
      char toCheck = buffer[(*i)++];
      if (!isdigit(toCheck)) {
        return false;
      }
    }
    return true;
}
 
static bool checkValidVersionBytes(const char* buffer) {
    // See READ_DATA_LENGTH comments above for a description of the format.
    size_t i = 0;
    if (!checkDigits(buffer, 3, &i)) {
      return false;
    }
    if (buffer[i++] != '.') {
      return false;
    }
    if (!checkDigits(buffer, 3, &i)) {
      return false;
    }
    if (buffer[i++] != '|') {
      return false;
    }
    if (!checkDigits(buffer, 4, &i)) {
      return false;
    }
    // Ignore the last character. It is assumed to be a letter but we don't check because it's not
    // obvious what would happen at 'z'.
    return true;
}
 
/* Return the parent directory of dirName. */
static std::string getParentDir(const std::string& dirName) {
    char *cMutableDirName = strdup(dirName.c_str());
    std::string parentDir = dirname(cMutableDirName);
    free(cMutableDirName);
    return parentDir;
}
 
/* Deletes a single file, symlink or directory. Called from nftw(). */
static int deleteFn(const char* fpath, const struct stat*, int typeflag, struct FTW*) {
    LOG(DEBUG) << "Inspecting " << fpath;
    switch (typeflag) {
    case FTW_F:
    case FTW_SL:
        LOG(DEBUG) << "Unlinking " << fpath;
        if (unlink(fpath)) {
            PLOG(WARNING) << "Failed to unlink file/symlink " << fpath;
        }
        break;
    case FTW_D:
    case FTW_DP:
        LOG(DEBUG) << "Removing dir " << fpath;
        if (rmdir(fpath)) {
            PLOG(WARNING) << "Failed to remove dir " << fpath;
        }
        break;
    default:
        LOG(WARNING) << "Unsupported file type " << fpath << ": " << typeflag;
        break;
    }
    return 0;
}
 
enum PathStatus { ERR, NONE, IS_DIR, IS_REG, UNKNOWN };
 
static PathStatus checkPath(const std::string& path) {
    struct stat buf;
    if (stat(path.c_str(), &buf) != 0) {
        if (errno != ENOENT) {
            PLOG(WARNING) << "Unable to stat " << path;
            return ERR;
        }
        return NONE;
    }
    return S_ISDIR(buf.st_mode) ? IS_DIR : S_ISREG(buf.st_mode) ? IS_REG : UNKNOWN;
}
 
/*
 * Deletes fileToDelete and returns true if it is successful. If fileToDelete is not a file or
 * cannot be accessed this method returns false.
 */
static bool deleteFile(const std::string& fileToDelete) {
    // Check whether the file exists.
    PathStatus pathStatus = checkPath(fileToDelete);
    if (pathStatus == NONE) {
        LOG(INFO) << "Path " << fileToDelete << " does not exist";
        return true;
    }
    if (pathStatus != IS_REG) {
        LOG(WARNING) << "Path " << fileToDelete << " failed to stat() or is not a file.";
        return false;
    }
 
    // Attempt the deletion.
    int rc = unlink(fileToDelete.c_str());
    if (rc != 0) {
        PLOG(WARNING) << "unlink() failed for " << fileToDelete;
    }
    return rc == 0;
}
 
/*
 * Deletes dirToDelete and returns true if it is successful in removing or moving the directory out
 * of the way. If dirToDelete does not exist this function does nothing and returns true. If
 * dirToDelete is not a directory or cannot be accessed this method returns false.
 *
 * During deletion, this function first renames the directory to a temporary name. If the temporary
 * directory cannot be created, or the directory cannot be renamed, false is returned. After the
 * rename, deletion of files and subdirs beneath the directory is performed on a "best effort"
 * basis. Symlinks beneath the directory are not followed.
 */
static bool deleteDir(const std::string& dirToDelete) {
    // Check whether the dir exists.
    int pathStatus = checkPath(dirToDelete);
    if (pathStatus == NONE) {
        LOG(INFO) << "Path " << dirToDelete << " does not exist";
        return true;
    }
    if (pathStatus != IS_DIR) {
        LOG(WARNING) << "Path " << dirToDelete << " failed to stat() or is not a directory.";
        return false;
    }
 
    // First, rename dirToDelete.
 
    std::string tempDirNameTemplate = getParentDir(dirToDelete);
    tempDirNameTemplate += "/tempXXXXXX";
 
    // Create an empty directory with the temporary name. For this we need a non-const char*.
    std::vector<char> tempDirName(tempDirNameTemplate.length() + 1);
    strcpy(&tempDirName[0], tempDirNameTemplate.c_str());
    if (mkdtemp(&tempDirName[0]) == nullptr) {
        PLOG(WARNING) << "Unable to create a temporary directory: " << tempDirNameTemplate;
        return false;
    }
 
    // Rename dirToDelete to tempDirName (replacing the empty tempDirName directory created above).
    int rc = rename(dirToDelete.c_str(), &tempDirName[0]);
    if (rc == -1) {
        PLOG(WARNING) << "Unable to rename directory from " << dirToDelete << " to "
                << &tempDirName[0];
        return false;
    }
 
    // Recursively delete contents of tempDirName.
 
    rc = nftw(&tempDirName[0], deleteFn, 10 /* openFiles */,
            FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
    if (rc == -1) {
        LOG(INFO) << "Could not delete directory: " << &tempDirName[0];
    }
    return true;
}
 
/*
 * Deletes the timezone update distro directory.
 */
static void deleteUpdateDistroDir(const std::string& distroDirName) {
    LOG(INFO) << "Removing: " << distroDirName;
    if (!deleteDir(distroDirName)) {
        LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
    }
}
 
static void handleStagedUninstall(const std::string& dataStagedDirName,
                                  const std::string& dataCurrentDirName,
                                  const PathStatus dataCurrentDirStatus) {
    LOG(INFO) << "Staged operation is an uninstall.";
 
    // Delete the current install directory.
    switch (dataCurrentDirStatus) {
        case NONE:
            // This is unexpected: No uninstall should be staged if there is nothing to
            // uninstall. Carry on anyway.
            LOG(WARNING) << "No current install to delete.";
            break;
        case IS_DIR:
            // This is normal. Delete the current install dir.
            if (!deleteDir(dataCurrentDirName)) {
                LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
                             << " was not successful";
                // If this happens we don't know whether we were able to delete or not. We don't
                // delete the staged operation so it will be retried next boot unless overridden.
                return;
            }
            break;
        case IS_REG:
        default:
            // This is unexpected: We can try to delete the unexpected file and carry on.
            LOG(WARNING) << "Current distro dir " << dataCurrentDirName
                         << " is not actually a directory. Attempting deletion.";
            if (!deleteFile(dataCurrentDirName)) {
                LOG(WARNING) << "Could not delete " << dataCurrentDirName;
                return;
            }
            break;
    }
 
    // Delete the staged uninstall dir.
    if (!deleteDir(dataStagedDirName)) {
        LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
                     << " was not successful";
        // If this happens we don't know whether we were able to delete the staged operation
        // or not.
        return;
    }
    LOG(INFO) << "Staged uninstall complete.";
}
 
static void handleStagedInstall(const std::string& dataStagedDirName,
                                const std::string& dataCurrentDirName,
                                const PathStatus dataCurrentDirStatus) {
    LOG(INFO) << "Staged operation is an install.";
 
    switch (dataCurrentDirStatus) {
        case NONE:
            // This is expected: This is the first install.
            LOG(INFO) << "No current install to replace.";
            break;
        case IS_DIR:
            // This is expected: We are replacing an existing install.
            // Delete the current dir so we can replace it.
            if (!deleteDir(dataCurrentDirName)) {
                LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
                             << " was not successful";
                // If this happens, we cannot proceed.
                return;
            }
            break;
        case IS_REG:
        default:
            // This is unexpected: We can try to delete the unexpected file and carry on.
            LOG(WARNING) << "Current distro dir " << dataCurrentDirName
                         << " is not actually a directory. Attempting deletion.";
            if (!deleteFile(dataCurrentDirName)) {
                LOG(WARNING) << "Could not delete " << dataCurrentDirName;
                return;
            }
            break;
    }
 
    // Move the staged dir so it is the new current dir, completing the install.
    LOG(INFO) << "Moving " << dataStagedDirName << " to " << dataCurrentDirName;
    int rc = rename(dataStagedDirName.c_str(), dataCurrentDirName.c_str());
    if (rc == -1) {
        PLOG(WARNING) << "Unable to rename directory from " << dataStagedDirName << " to "
                      << &dataCurrentDirName[0];
        return;
    }
 
    LOG(INFO) << "Staged install complete.";
}
/*
 * Process a staged operation if there is one.
 */
static void processStagedOperation(const std::string& dataStagedDirName,
                                   const std::string& dataCurrentDirName) {
    PathStatus dataStagedDirStatus = checkPath(dataStagedDirName);
 
    // Exit early for the common case.
    if (dataStagedDirStatus == NONE) {
        LOG(DEBUG) << "No staged time zone operation.";
        return;
    }
 
    // Check known directory names are in a good starting state.
    if (dataStagedDirStatus != IS_DIR) {
        LOG(WARNING) << "Staged distro dir " << dataStagedDirName
                     << " could not be accessed or is not a directory."
                     << " stagedDirStatus=" << dataStagedDirStatus;
        return;
    }
 
    // dataStagedDirStatus == IS_DIR.
 
    // Work out whether there is anything currently installed.
    PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
    if (dataCurrentDirStatus == ERR) {
        LOG(WARNING) << "Current install dir " << dataCurrentDirName << " could not be accessed"
                     << " dataCurrentDirStatus=" << dataCurrentDirStatus;
        return;
    }
 
    // We must perform the staged operation.
 
    // Check to see if the staged directory contains an uninstall or an install operation.
    std::string uninstallTombStoneFile(dataStagedDirName);
    uninstallTombStoneFile += UNINSTALL_TOMBSTONE_FILE_NAME;
    int uninstallTombStoneFileStatus = checkPath(uninstallTombStoneFile);
    if (uninstallTombStoneFileStatus != IS_REG && uninstallTombStoneFileStatus != NONE) {
        // Error case.
        LOG(WARNING) << "Unable to determine if the staged operation is an uninstall.";
        return;
    }
    if (uninstallTombStoneFileStatus == IS_REG) {
        handleStagedUninstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
    } else {
        // uninstallTombStoneFileStatus == NONE meaning this is a staged install.
        handleStagedInstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
    }
}
 
/*
 * After a platform update it is likely that the "base" timezone data found on the device will be
 * newer than the version found in the data partition. This tool detects this case and removes the
 * version in /data.
 *
 * Note: This code is related to code in com.android.server.updates.TzDataInstallReceiver. The
 * paths for the metadata and current timezone data must match.
 *
 * Typically on device the two args will be:
 *   /apex/com.google.runtime/etc/tz /data/misc/zoneinfo
 *
 * See usage() for usage notes.
 */
int main(int argc, char* argv[]) {
    if (argc != 3) {
        usage();
        return 1;
    }
 
    const char* baseZoneInfoDir = argv[1];
    const char* dataZoneInfoDir = argv[2];
 
    std::string dataStagedDirName(dataZoneInfoDir);
    dataStagedDirName += STAGED_DIR_NAME;
 
    std::string dataCurrentDirName(dataZoneInfoDir);
    dataCurrentDirName += CURRENT_DIR_NAME;
 
    // Check for an process any staged operation.
    // If the staged operation could not be handled we still have to validate the current installed
    // directory so we do not check for errors and do not quit early.
    processStagedOperation(dataStagedDirName, dataCurrentDirName);
 
    // Check the distro directory exists. If it does not, exit quickly: nothing to do.
    PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
    if (dataCurrentDirStatus == NONE) {
        LOG(INFO) << "timezone distro dir " << dataCurrentDirName
                << " does not exist. No action required.";
        return 0;
    }
 
    // If the distro directory path is not a directory or we can't stat() the path, exit with a
    // warning: either there's a problem accessing storage or the world is not as it should be;
    // nothing to do.
    if (dataCurrentDirStatus != IS_DIR) {
        LOG(WARNING) << "Current distro dir " << dataCurrentDirName
                << " could not be accessed or is not a directory. result=" << dataCurrentDirStatus;
        return 2;
    }
 
    // Check the installed distro version.
    std::string distroVersionFileName(dataCurrentDirName);
    distroVersionFileName += DISTRO_VERSION_FILENAME;
    std::vector<char> distroVersion;
    distroVersion.reserve(READ_DATA_LENGTH);
    bool distroVersionReadOk =
            readBytes(distroVersionFileName, distroVersion.data(), READ_DATA_LENGTH);
    if (!distroVersionReadOk) {
        LOG(WARNING) << "distro version file " << distroVersionFileName
                << " does not exist or is too short. Deleting distro dir.";
        // Implies the contents of the data partition is corrupt in some way. Try to clean up.
        deleteUpdateDistroDir(dataCurrentDirName);
        return 3;
    }
 
    if (!checkValidVersionBytes(distroVersion.data())) {
        LOG(WARNING) << "distro version file " << distroVersionFileName
                << " is not valid. Deleting distro dir.";
        // Implies the contents of the data partition is corrupt in some way. Try to clean up.
        deleteUpdateDistroDir(dataCurrentDirName);
        return 4;
    }
 
    // Check the base tz data set version.
    std::string baseVersionFileName(baseZoneInfoDir);
    baseVersionFileName += BASE_VERSION_FILENAME;
    std::vector<char> baseVersion;
    baseVersion.reserve(READ_DATA_LENGTH);
    bool baseVersionReadOk =
            readBytes(baseVersionFileName, baseVersion.data(), READ_DATA_LENGTH);
    if (!baseVersionReadOk) {
        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
        LOG(WARNING) << baseVersionFileName << " does not exist or could not be opened";
        return 6;
    }
 
    if (!checkValidVersionBytes(baseVersion.data())) {
        // Implies the contents of the system partition is corrupt in some way. Nothing we can do.
        LOG(WARNING) << baseVersionFileName << " is not valid.";
        return 7;
    }
 
    std::string actualDistroVersion = std::string(distroVersion.data(), FORMAT_VERSION_LEN);
    std::string baseTzVersion = std::string(baseVersion.data(), FORMAT_VERSION_LEN);
 
    // Check the first 3 bytes of the format version: these are the major version (e.g. 001).
    // It must match the one we support exactly to be ok.
    if (strncmp(
            &distroVersion[FORMAT_MAJOR_VERSION_IDX],
            &baseTzVersion[FORMAT_MAJOR_VERSION_IDX],
            FORMAT_MAJOR_VERSION_LEN) != 0) {
 
        LOG(INFO) << "distro version file " << distroVersionFileName
                << " major version is not the required version " << baseTzVersion
                << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
        // This implies there has been an OTA and the installed distro is not compatible with a
        // new version of Android. Remove the installed distro.
        deleteUpdateDistroDir(dataCurrentDirName);
        return 5;
    }
 
    // Check the last 3 bytes of the format version: these are the minor version (e.g. 001).
    // If the version in the distro is < the minor version required by this device it cannot be
    // used.
    if (strncmp(
            &distroVersion[FORMAT_MINOR_VERSION_IDX],
            &baseTzVersion[FORMAT_MINOR_VERSION_IDX],
            FORMAT_MINOR_VERSION_LEN) < 0) {
 
        LOG(INFO) << "distro version file " << distroVersionFileName
                << " minor version is not the required version " << baseTzVersion
                << ", was \"" << actualDistroVersion << "\". Deleting distro dir.";
        // This implies there has been an OTA and the installed distro is not compatible with a
        // new version of Android. Remove the installed distro.
        deleteUpdateDistroDir(dataCurrentDirName);
        return 5;
    }
 
    // Compare the distro rules version against the system rules version.
    if (strncmp(
            &baseVersion[VERSION_RULES_IDX],
            &distroVersion[VERSION_RULES_IDX],
            RULES_VERSION_LEN) <= 0) {
        LOG(INFO) << "Found an installed distro but it is valid. No action taken.";
        // Implies there is an installed update, but it is good.
        return 0;
    }
 
    // Implies there has been an OTA and the system version of the timezone rules is now newer
    // than the version installed in /data. Remove the installed distro.
    LOG(INFO) << "timezone distro in " << dataCurrentDirName << " is older than data in "
            << baseVersionFileName << "; fixing...";
 
    deleteUpdateDistroDir(dataCurrentDirName);
    return 0;
}