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)) {
88 if (errno == EEXIST) {
90 return WIMLIB_ERR_LINK;
91 if ((*makelink)(oldpath, newpath))
92 return WIMLIB_ERR_LINK;
95 return WIMLIB_ERR_LINK;
100 unix_create_hardlink(const tchar *oldpath, const tchar *newpath,
101 struct apply_ctx *ctx)
103 return unix_makelink(oldpath, newpath, link);
107 unix_create_symlink(const tchar *oldpath, const tchar *newpath,
108 struct apply_ctx *ctx)
110 return unix_makelink(oldpath, newpath, symlink);
114 unix_extract_unnamed_stream(file_spec_t file,
115 struct wim_lookup_table_entry *lte,
116 struct apply_ctx *ctx)
118 const char *path = file.path;
123 raw_fd = open(path, O_WRONLY | O_TRUNC);
125 return WIMLIB_ERR_OPEN;
126 filedes_init(&fd, raw_fd);
127 ret = extract_wim_resource_to_fd(lte, &fd, wim_resource_size(lte));
128 if (filedes_close(&fd) && !ret)
129 ret = WIMLIB_ERR_WRITE;
134 unix_set_unix_data(const tchar *path, const struct wimlib_unix_data *data,
135 struct apply_ctx *ctx)
139 if (lstat(path, &stbuf))
140 return WIMLIB_ERR_SET_SECURITY;
141 if (!S_ISLNK(stbuf.st_mode))
142 if (chmod(path, data->mode))
143 return WIMLIB_ERR_SET_SECURITY;
144 if (lchown(path, data->uid, data->gid))
145 return WIMLIB_ERR_SET_SECURITY;
150 unix_set_timestamps(const tchar *path, u64 creation_time, u64 last_write_time,
151 u64 last_access_time, struct apply_ctx *ctx)
155 #ifdef HAVE_UTIMENSAT
156 /* Convert the WIM timestamps, which are accurate to 100 nanoseconds,
157 * into `struct timespec's for passing to utimensat(), which is accurate
158 * to 1 nanosecond. */
160 struct timespec ts[2];
161 ts[0] = wim_timestamp_to_timespec(last_access_time);
162 ts[1] = wim_timestamp_to_timespec(last_write_time);
163 ret = utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW);
171 /* utimensat() not implemented or not available */
173 /* Convert the WIM timestamps, which are accurate to 100
174 * nanoseconds, into `struct timeval's for passing to lutimes(),
175 * which is accurate to 1 microsecond. */
176 struct timeval tv[2];
177 tv[0] = wim_timestamp_to_timeval(last_access_time);
178 tv[1] = wim_timestamp_to_timeval(last_write_time);
179 ret = lutimes(path, tv);
186 /* utimensat() and lutimes() both not implemented or not
189 /* Convert the WIM timestamps, which are accurate to 100
190 * nanoseconds, into a `struct utimbuf's for passing to
191 * utime(), which is accurate to 1 second. */
193 buf.actime = wim_timestamp_to_unix(last_access_time);
194 buf.modtime = wim_timestamp_to_unix(last_write_time);
195 ret = utime(path, &buf);
199 return WIMLIB_ERR_SET_TIMESTAMPS;
203 const struct apply_operations unix_apply_ops = {
206 .start_extract = unix_start_extract,
207 .create_file = unix_create_file,
208 .create_directory = unix_create_directory,
209 .create_hardlink = unix_create_hardlink,
210 .create_symlink = unix_create_symlink,
211 .extract_unnamed_stream = unix_extract_unnamed_stream,
212 .set_unix_data = unix_set_unix_data,
213 .set_timestamps = unix_set_timestamps,
215 .path_separator = '/',
216 .path_max = PATH_MAX,
218 .requires_target_in_paths = 1,
219 .supports_case_sensitive_filenames = 1,
222 #endif /* !__WIN32__ */