1 /*
2  * Copyright (c) 2007 Vreixo Formoso
3  * Copyright (c) 2009 - 2015 Thomas Schmitt
4  *
5  * This file is part of the libisofs project; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License version 2
7  * or later as published by the Free Software Foundation.
8  * See COPYING file for details.
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "../config.h"
13 #endif
14 
15 /* libisofs.h defines aaip_xinfo_func */
16 #include "libisofs.h"
17 
18 #include "builder.h"
19 #include "node.h"
20 #include "fsource.h"
21 #include "image.h"
22 #include "aaip_0_2.h"
23 #include "util.h"
24 #include "messages.h"
25 
26 #include <stdlib.h>
27 #include <string.h>
28 #include <limits.h>
29 #include <stdio.h>
30 
31 
32 
iso_node_builder_ref(IsoNodeBuilder * builder)33 void iso_node_builder_ref(IsoNodeBuilder *builder)
34 {
35     ++builder->refcount;
36 }
37 
iso_node_builder_unref(IsoNodeBuilder * builder)38 void iso_node_builder_unref(IsoNodeBuilder *builder)
39 {
40     if (--builder->refcount == 0) {
41         /* free private data */
42         builder->free(builder);
43         free(builder);
44     }
45 }
46 
47 static
default_create_file(IsoNodeBuilder * builder,IsoImage * image,IsoFileSource * src,IsoFile ** file)48 int default_create_file(IsoNodeBuilder *builder, IsoImage *image,
49                         IsoFileSource *src, IsoFile **file)
50 {
51     int ret;
52     struct stat info;
53     IsoStream *stream;
54     IsoFile *node;
55     char *name;
56 
57     if (builder == NULL || src == NULL || file == NULL) {
58         return ISO_NULL_POINTER;
59     }
60 
61     ret = iso_file_source_stat(src, &info);
62     if (ret < 0) {
63         return ret;
64     }
65 
66     /* this will fail if src is a dir, is not accessible... */
67     ret = iso_file_source_stream_new(src, &stream);
68     if (ret < 0) {
69         return ret;
70     }
71 
72     /* take a ref to the src, as stream has taken our ref */
73     iso_file_source_ref(src);
74 
75     name = iso_file_source_get_name(src);
76     if ((int) strlen(name) > image->truncate_length) {
77         ret = iso_truncate_rr_name(image->truncate_mode,
78                                    image->truncate_length, name, 0);
79         if (ret < 0) {
80             iso_stream_unref(stream);
81             free(name);
82             return ret;
83         }
84     }
85     ret = iso_node_new_file(name, stream, &node);
86     if (ret < 0) {
87         iso_stream_unref(stream);
88         free(name);
89         return ret;
90     }
91 
92     /* fill node fields */
93     iso_node_set_permissions((IsoNode*)node, info.st_mode);
94     iso_node_set_uid((IsoNode*)node, info.st_uid);
95     iso_node_set_gid((IsoNode*)node, info.st_gid);
96     iso_node_set_atime((IsoNode*)node, info.st_atime);
97     iso_node_set_mtime((IsoNode*)node, info.st_mtime);
98     iso_node_set_ctime((IsoNode*)node, info.st_ctime);
99     iso_node_set_uid((IsoNode*)node, info.st_uid);
100 
101     *file = node;
102     return ISO_SUCCESS;
103 }
104 
105 static
default_create_node(IsoNodeBuilder * builder,IsoImage * image,IsoFileSource * src,char * in_name,IsoNode ** node)106 int default_create_node(IsoNodeBuilder *builder, IsoImage *image,
107                         IsoFileSource *src, char *in_name, IsoNode **node)
108 {
109     int ret, name_is_attached = 0;
110     struct stat info;
111     IsoNode *new;
112     IsoFilesystem *fs;
113     char *name = NULL;
114     unsigned char *aa_string = NULL;
115     char *a_text = NULL, *d_text = NULL;
116     char *dest = NULL;
117     IsoSymlink *link;
118 
119     if (builder == NULL || src == NULL || node == NULL) {
120         {ret = ISO_NULL_POINTER; goto ex;}
121     }
122 
123     /* get info about source */
124     if (iso_tree_get_follow_symlinks(image)) {
125         ret = iso_file_source_stat(src, &info);
126     } else {
127         ret = iso_file_source_lstat(src, &info);
128     }
129     if (ret < 0) {
130         goto ex;
131     }
132 
133     if (in_name == NULL) {
134         name = iso_file_source_get_name(src);
135     } else {
136         name = strdup(in_name);
137         if (name == NULL) {
138             ret = ISO_OUT_OF_MEM; goto ex;
139         }
140     }
141 
142     if ((int) strlen(name) > image->truncate_length) {
143         ret = iso_truncate_rr_name(image->truncate_mode,
144                                    image->truncate_length, name, 0);
145         if (ret < 0)
146             goto ex;
147     }
148     fs = iso_file_source_get_filesystem(src);
149     new = NULL;
150 
151     switch (info.st_mode & S_IFMT) {
152     case S_IFREG:
153         {
154             /* source is a regular file */
155             IsoStream *stream;
156             IsoFile *file;
157             ret = iso_file_source_stream_new(src, &stream);
158             if (ret < 0) {
159                 break;
160             }
161             /* take a ref to the src, as stream has taken our ref */
162             iso_file_source_ref(src);
163 
164             /* create the file */
165             ret = iso_node_new_file(name, stream, &file);
166             if (ret < 0) {
167                 iso_stream_unref(stream);
168             }
169             new = (IsoNode*) file;
170         }
171         break;
172     case S_IFDIR:
173         {
174             /* source is a directory */
175             IsoDir *dir;
176             ret = iso_node_new_dir(name, &dir);
177             new = (IsoNode*)dir;
178         }
179         break;
180     case S_IFLNK:
181         {
182             /* source is a symbolic link */
183             LIBISO_ALLOC_MEM(dest, char, LIBISOFS_NODE_PATH_MAX);
184             ret = iso_file_source_readlink(src, dest, LIBISOFS_NODE_PATH_MAX);
185             if (ret < 0) {
186                 break;
187             }
188             ret = iso_node_new_symlink(name, strdup(dest), &link);
189             new = (IsoNode*) link;
190             if (fs != NULL) {
191                 link->fs_id = fs->get_id(fs);
192                 if (link->fs_id != 0) {
193                     link->st_ino = info.st_ino;
194                     link->st_dev = info.st_dev;
195                 }
196             }
197         }
198         break;
199     case S_IFSOCK:
200     case S_IFBLK:
201     case S_IFCHR:
202     case S_IFIFO:
203         {
204             /* source is an special file */
205             IsoSpecial *special;
206             ret = iso_node_new_special(name, info.st_mode, info.st_rdev,
207                                        &special);
208             new = (IsoNode*) special;
209             if (fs != NULL) {
210                 special->fs_id = fs->get_id(fs);
211                 if (special->fs_id != 0) {
212                     special->st_ino = info.st_ino;
213                     special->st_dev = info.st_dev;
214                 }
215             }
216         }
217         break;
218     default:
219         ret = ISO_BAD_FSRC_FILETYPE;
220         goto ex;
221     }
222 
223     if (ret < 0)
224         goto ex;
225     name_is_attached = 1;
226 
227     /* fill fields */
228     iso_node_set_perms_internal(new, info.st_mode, 1);
229     iso_node_set_uid(new, info.st_uid);
230     iso_node_set_gid(new, info.st_gid);
231     iso_node_set_atime(new, info.st_atime);
232     iso_node_set_mtime(new, info.st_mtime);
233     iso_node_set_ctime(new, info.st_ctime);
234     iso_node_set_uid(new, info.st_uid);
235 
236     /* Eventually set S_IRWXG from ACL */
237     if (image->builder_ignore_acl) {
238         ret = iso_file_source_get_aa_string(src, &aa_string, 4);
239         if (ret >= 0 && aa_string != NULL)
240             iso_aa_get_acl_text(aa_string, info.st_mode, &a_text, &d_text, 16);
241         if (ret >= 0 && a_text != NULL) {
242             aaip_cleanout_st_mode(a_text, &(info.st_mode), 4 | 16);
243             iso_node_set_perms_internal(new, info.st_mode, 1);
244         }
245         iso_aa_get_acl_text(aa_string, info.st_mode, &a_text, &d_text,
246                             1 << 15); /* free ACL texts */
247         if(aa_string != NULL)
248             free(aa_string);
249         aa_string = NULL;
250     }
251 
252     /* Obtain ownership of eventual AAIP string */
253     ret = iso_file_source_get_aa_string(src, &aa_string,
254             1 | (image->builder_ignore_acl << 1) |
255                 (image->builder_ignore_ea << 2) |
256                 (image->builder_take_all_ea << 3));
257     if(ret == 2)
258       image->blind_on_local_get_attrs = 1;
259     if (ret > 0 && aa_string != NULL) {
260         ret = iso_node_add_xinfo(new, aaip_xinfo_func, aa_string);
261         if (ret < 0)
262             goto ex;
263     } else if(aa_string != NULL) {
264         free(aa_string);
265     }
266 
267     *node = new;
268 
269     ret = ISO_SUCCESS;
270 ex:;
271     if (name != NULL && !name_is_attached)
272         free(name);
273     LIBISO_FREE_MEM(dest);
274     return ret;
275 }
276 
277 static
default_free(IsoNodeBuilder * builder)278 void default_free(IsoNodeBuilder *builder)
279 {
280     /* The .free() method of IsoNodeBuilder shall free private data but not
281        the builder itself. The latter is done in iso_node_builder_unref().
282     */
283     return;
284 }
285 
iso_node_basic_builder_new(IsoNodeBuilder ** builder)286 int iso_node_basic_builder_new(IsoNodeBuilder **builder)
287 {
288     IsoNodeBuilder *b;
289 
290     if (builder == NULL) {
291         return ISO_NULL_POINTER;
292     }
293 
294     b = malloc(sizeof(IsoNodeBuilder));
295     if (b == NULL) {
296         return ISO_OUT_OF_MEM;
297     }
298 
299     b->refcount = 1;
300     b->create_file_data = NULL;
301     b->create_node_data = NULL;
302     b->create_file = default_create_file;
303     b->create_node = default_create_node;
304     b->free = default_free;
305 
306     *builder = b;
307     return ISO_SUCCESS;
308 }
309