L4Re/departure

libe2access/host/op_copy_in.c

391:bc65615a8fed
2022-06-30 Paul Boddie Added missing structure members. mmap-region-flags
     1 /*     2  * Copy a file into a filesystem.     3  *     4  * Copyright (C) 2019, 2022 Paul Boddie <paul@boddie.org.uk>     5  *     6  * This program is free software; you can redistribute it and/or     7  * modify it under the terms of the GNU General Public License as     8  * published by the Free Software Foundation; either version 2 of     9  * the License, or (at your option) any later version.    10  *    11  * This program is distributed in the hope that it will be useful,    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    14  * GNU General Public License for more details.    15  *    16  * You should have received a copy of the GNU General Public License    17  * along with this program; if not, write to the Free Software    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor,    19  * Boston, MA  02110-1301, USA    20  */    21     22 #include <stdio.h>    23     24 #include <sys/stat.h>    25     26 #include <ext2fs/ext2fs.h>    27     28 #include "file.h"    29 #include "image.h"    30 #include "path.h"    31 #include "session.h"    32     33     34     35 /* Copy buffer size. */    36     37 static int BUFSIZE = 4096;    38     39     40     41 /* Alternative metadata set by options. */    42     43 extern struct metadata md;    44     45     46     47 /* Copy a file into the filesystem image. */    48     49 static int _copy_file_in(const char *filename, ext2_filsys fs,    50                          ext2_ino_t ino_file, int flags)    51 {    52     int retval = 0;    53     ext2_file_t file;    54     55     /* Copying details. */    56     57     FILE *fp;    58     char buf[BUFSIZE];    59     size_t got;    60     unsigned int written;    61     62     /* Open a file in the target directory. */    63     64     if (ext2fs_file_open(fs, ino_file, flags, &file))    65         return 1;    66     67     /* Truncate the file, if overwriting. */    68     69     if (!(flags & EXT2_FILE_CREATE))    70         ext2fs_file_set_size2(file, 0);    71     72     /* Open the file in the source directory. */    73     74     fp = fopen(filename, "r");    75     76     /* Copy the file content. */    77     78     if (fp != NULL)    79     {    80         while (got = fread(buf, sizeof(char), BUFSIZE, fp))    81         {    82             while (got)    83             {    84                 if (ext2fs_file_write(file, buf, got, &written))    85                 {    86                     retval = 1;    87                     goto close_files;    88                 }    89                 got -= written;    90             }    91         }    92     }    93     94 close_files:    95     fclose(fp);    96     ext2fs_file_flush(file);    97     ext2fs_file_close(file);    98     99     return retval;   100 }   101    102 /* Make a new object using the given function. */   103    104 static int _make_object(ext2_filsys fs, const char *filename,   105                         ext2_ino_t ino_parent, const char *basename,   106                         ext2_ino_t *ino_target,   107                         errcode_t (*fn)(ext2_filsys, ext2_ino_t, const char *,   108                                         __u16, __u16, __u16, ext2_ino_t *))   109 {   110     errcode_t retval;   111     struct stat st;   112    113     /* Obtain the metadata. */   114    115     if (lstat(filename, &st))   116     {   117         fprintf(stderr, "Failed to read object metadata: %s\n", filename);   118         return 1;   119     }   120    121     retval = fn(fs, ino_parent, basename, st.st_mode & ~md.mask,   122                 md.have_uid ? md.uid : st.st_uid,   123                 md.have_gid ? md.gid : st.st_gid,   124                 ino_target);   125    126     if (retval)   127     {   128         fprintf(stderr, "Failed to create object: %s\n", filename);   129         return 1;   130     }   131    132     return 0;   133 }   134    135 /* Copy a source file from the external environment into the filesystem. */   136    137 static int _copy_in(ext2_filsys fs, const char *filename, ext2_ino_t ino_target,   138                     const char *basename)   139 {   140     errcode_t retval;   141     int flags;   142    143     /* By default, treat the target as a new object. */   144    145     ext2_ino_t ino_parent = ino_target;   146     int target_is_new = 1;   147    148     /* Source file details. */   149    150     struct stat st;   151    152     /* Without a basename, the target exists and is either a directory, into   153        which the source file shall be copied, or it is a file that shall be   154        overwritten (for which the basename is irrelevant). */   155    156     if (basename == NULL)   157     {   158         basename = path_basename(filename);   159         target_is_new = image_isdir_by_inode(fs, ino_target);   160     }   161    162     /* Directories are created with the same metadata. */   163    164     if (isdir(filename))   165     {   166         if (!target_is_new)   167         {   168             fprintf(stderr, "Directory cannot be copied as it already exists: %s\n", filename);   169             return 1;   170         }   171    172         if (_make_object(fs, filename, ino_parent, basename, &ino_target,   173                          image_make_dir))   174             return 1;   175     }   176    177     /* Files are copied. */   178    179     else if (isfile(filename))   180     {   181         flags = EXT2_FILE_WRITE;   182    183         /* Obtain the inode for the target file. */   184    185         if (target_is_new)   186         {   187             if (_make_object(fs, filename, ino_parent, basename, &ino_target,   188                              image_create_file))   189                 return 1;   190    191             flags |= EXT2_FILE_CREATE;   192         }   193    194         /* NOTE: Overwrite/update metadata where appropriate. */   195    196         if (_copy_file_in(filename, fs, ino_target, flags))   197         {   198             fprintf(stderr, "Failed to copy file: %s\n", filename);   199             return 1;   200         }   201     }   202 }   203    204 /* Copy source files from the external environment into the filesystem image. */   205    206 int copy_in(ext2_filsys fs, int argc, char *argv[])   207 {   208     errcode_t retval;   209     int i;   210    211     /* Target filename details. */   212    213     const char *target = argv[argc - 1];   214     const char *target_remaining = target;   215     const char *basename;   216    217     /* Target file and directory details. */   218    219     int target_is_file;   220     ext2_ino_t ino_target;   221    222     /* Locate the target and test whether it is a file or a directory. */   223    224     if (image_resolve_by_path(fs, &target_remaining, &ino_target))   225     {   226         /* Only a non-existent file in an existing directory is permitted. */   227    228         if (!image_isdir_by_inode(fs, ino_target) || !path_is_leafname(target_remaining))   229         {   230             fprintf(stderr, "Target not found: %s\n", target);   231             return 1;   232         }   233    234         /* Any absent target leaves the basename remaining.   235            The resolved target is the parent directory. */   236    237         target_is_file = 0;   238         basename = target_remaining;   239     }   240     else   241     {   242         /* Any present target can be a file or directory.   243            The resolved target is the actual target. */   244    245         target_is_file = image_isfile_by_inode(fs, ino_target);   246         basename = NULL;   247     }   248    249     /* Only permit a target file when one source file is given. */   250    251     if (target_is_file)   252     {   253         if (argc > 2)   254         {   255             fprintf(stderr, "Target can only be a file when copying a single file: %s\n", target);   256             return 1;   257         }   258     }   259     else if (!image_isdir_by_inode(fs, ino_target))   260     {   261         fprintf(stderr, "Target is not a directory: %s\n", target);   262         return 1;   263     }   264    265     /* Copy each source object to the target directory. */   266    267     for (i = 0; i < argc - 1; i++)   268         if (_copy_in(fs, argv[i], ino_target, basename))   269             return 1;   270    271     return 0;   272 }   273    274 /* vim: tabstop=4 expandtab shiftwidth=4   275 */