2 * unix_apply.c - Code to apply files from a WIM image on UNIX.
6 * Copyright (C) 2012, 2013 Eric Biggers
8 * This file is part of wimlib, a library for working with WIM files.
10 * wimlib is free software; you can redistribute it and/or modify it under the
11 * terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option)
15 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 * A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with wimlib; if not, see http://www.gnu.org/licenses/.
30 #include "wimlib/apply.h"
31 #include "wimlib/error.h"
32 #include "wimlib/lookup_table.h"
33 #include "wimlib/resource.h"
34 #include "wimlib/timestamp.h"
40 #include <sys/types.h>
48 unix_start_extract(const char *target, struct apply_ctx *ctx)
50 ctx->supported_features.hard_links = 1;
51 ctx->supported_features.symlink_reparse_points = 1;
52 ctx->supported_features.unix_data = 1;
57 unix_create_file(const char *path, struct apply_ctx *ctx, u64 *cookie_ret)
59 int fd = open(path, O_TRUNC | O_CREAT | O_WRONLY, 0644);
61 return WIMLIB_ERR_OPEN;
67 unix_create_directory(const tchar *path, struct apply_ctx *ctx, u64 *cookie_ret)
71 if (mkdir(path, 0755)) {
73 return WIMLIB_ERR_MKDIR;
74 if (lstat(path, &stbuf))
75 return WIMLIB_ERR_MKDIR;
77 if (!S_ISDIR(stbuf.st_mode))
78 return WIMLIB_ERR_MKDIR;
84 unix_makelink(const tchar *oldpath, const tchar *newpath,
85 int (*makelink)(const tchar *oldpath, const tchar *newpath))
87 if ((*makelink)(oldpath, newpath)) {
89 return WIMLIB_ERR_LINK;
91 return WIMLIB_ERR_LINK;
92 if ((*makelink)(oldpath, newpath))
93 return WIMLIB_ERR_LINK;
98 unix_create_hardlink(const tchar *oldpath, const tchar *newpath,
99 struct apply_ctx *ctx)
101 return unix_makelink(oldpath, newpath, link);
105 unix_create_symlink(const tchar *oldpath, const tchar *newpath,
106 struct apply_ctx *ctx)
108 return unix_makelink(oldpath, newpath, symlink);
112 unix_extract_unnamed_stream(file_spec_t file,
113 struct wim_lookup_table_entry *lte,
114 struct apply_ctx *ctx)
116 const char *path = file.path;
121 raw_fd = open(path, O_WRONLY | O_TRUNC);
123 return WIMLIB_ERR_OPEN;
124 filedes_init(&fd, raw_fd);
125 ret = extract_wim_resource_to_fd(lte, &fd, wim_resource_size(lte));
126 if (filedes_close(&fd) && !ret)
127 ret = WIMLIB_ERR_WRITE;
132 unix_set_unix_data(const tchar *path, const struct wimlib_unix_data *data,
133 struct apply_ctx *ctx)
137 if (lstat(path, &stbuf))
138 return WIMLIB_ERR_SET_SECURITY;
139 if (!S_ISLNK(stbuf.st_mode))
140 if (chmod(path, data->mode))
141 return WIMLIB_ERR_SET_SECURITY;
142 if (lchown(path, data->uid, data->gid))
143 return WIMLIB_ERR_SET_SECURITY;
148 unix_set_timestamps(const tchar *path, u64 creation_time, u64 last_write_time,
149 u64 last_access_time, struct apply_ctx *ctx)
153 #ifdef HAVE_UTIMENSAT
154 /* Convert the WIM timestamps, which are accurate to 100 nanoseconds,
155 * into `struct timespec's for passing to utimensat(), which is accurate
156 * to 1 nanosecond. */
158 struct timespec ts[2];
159 ts[0] = wim_timestamp_to_timespec(last_access_time);
160 ts[1] = wim_timestamp_to_timespec(last_write_time);
161 ret = utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW);
169 /* utimensat() not implemented or not available */
171 /* Convert the WIM timestamps, which are accurate to 100
172 * nanoseconds, into `struct timeval's for passing to lutimes(),
173 * which is accurate to 1 microsecond. */
174 struct timeval tv[2];
175 tv[0] = wim_timestamp_to_timeval(last_access_time);
176 tv[1] = wim_timestamp_to_timeval(last_write_time);
177 ret = lutimes(path, tv);
184 /* utimensat() and lutimes() both not implemented or not
187 /* Convert the WIM timestamps, which are accurate to 100
188 * nanoseconds, into a `struct utimbuf's for passing to
189 * utime(), which is accurate to 1 second. */
191 buf.actime = wim_timestamp_to_unix(last_access_time);
192 buf.modtime = wim_timestamp_to_unix(last_write_time);
193 ret = utime(path, &buf);
197 return WIMLIB_ERR_SET_TIMESTAMPS;
201 const struct apply_operations unix_apply_ops = {
204 .start_extract = unix_start_extract,
205 .create_file = unix_create_file,
206 .create_directory = unix_create_directory,
207 .create_hardlink = unix_create_hardlink,
208 .create_symlink = unix_create_symlink,
209 .extract_unnamed_stream = unix_extract_unnamed_stream,
210 .set_unix_data = unix_set_unix_data,
211 .set_timestamps = unix_set_timestamps,
213 .path_separator = '/',
214 .path_max = PATH_MAX,
216 .requires_target_in_paths = 1,
217 .supports_case_sensitive_filenames = 1,
220 #endif /* !__WIN32__ */