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)
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)
71 if (mkdir(path, 0755)) {
73 return WIMLIB_ERR_MKDIR;
74 if (lstat(path, &stbuf))
75 return WIMLIB_ERR_STAT;
77 if (!S_ISDIR(stbuf.st_mode))
78 return WIMLIB_ERR_NOTDIR;
84 unix_create_hardlink(const tchar *oldpath, const tchar *newpath,
85 struct apply_ctx *ctx)
87 if (link(oldpath, newpath))
88 return WIMLIB_ERR_LINK;
93 unix_create_symlink(const tchar *oldpath, const tchar *newpath,
94 struct apply_ctx *ctx)
96 if (symlink(oldpath, newpath))
97 return WIMLIB_ERR_LINK;
102 unix_extract_unnamed_stream(const tchar *path,
103 struct wim_lookup_table_entry *lte,
104 struct apply_ctx *ctx)
110 raw_fd = open(path, O_WRONLY | O_TRUNC);
112 return WIMLIB_ERR_OPEN;
113 filedes_init(&fd, raw_fd);
114 ret = extract_wim_resource_to_fd(lte, &fd, wim_resource_size(lte));
115 if (filedes_close(&fd) && !ret)
116 ret = WIMLIB_ERR_WRITE;
121 unix_set_unix_data(const tchar *path, const struct wimlib_unix_data *data,
122 struct apply_ctx *ctx)
126 if (lstat(path, &stbuf))
127 return WIMLIB_ERR_STAT;
128 if (!S_ISLNK(stbuf.st_mode))
129 if (chmod(path, data->mode))
130 return WIMLIB_ERR_SET_SECURITY;
131 if (lchown(path, data->uid, data->gid))
132 return WIMLIB_ERR_SET_SECURITY;
137 unix_set_timestamps(const tchar *path, u64 creation_time, u64 last_write_time,
138 u64 last_access_time, struct apply_ctx *ctx)
142 #ifdef HAVE_UTIMENSAT
143 /* Convert the WIM timestamps, which are accurate to 100 nanoseconds,
144 * into `struct timespec's for passing to utimensat(), which is accurate
145 * to 1 nanosecond. */
147 struct timespec ts[2];
148 ts[0] = wim_timestamp_to_timespec(last_access_time);
149 ts[1] = wim_timestamp_to_timespec(last_write_time);
150 ret = utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW);
158 /* utimensat() not implemented or not available */
160 /* Convert the WIM timestamps, which are accurate to 100
161 * nanoseconds, into `struct timeval's for passing to lutimes(),
162 * which is accurate to 1 microsecond. */
163 struct timeval tv[2];
164 tv[0] = wim_timestamp_to_timeval(last_access_time);
165 tv[1] = wim_timestamp_to_timeval(last_write_time);
166 ret = lutimes(path, tv);
173 /* utimensat() and lutimes() both not implemented or not
176 /* Convert the WIM timestamps, which are accurate to 100
177 * nanoseconds, into a `struct utimbuf's for passing to
178 * utime(), which is accurate to 1 second. */
180 buf.actime = wim_timestamp_to_unix(last_access_time);
181 buf.modtime = wim_timestamp_to_unix(last_write_time);
182 ret = utime(path, &buf);
186 return WIMLIB_ERR_SET_TIMESTAMPS;
190 const struct apply_operations unix_apply_ops = {
193 .start_extract = unix_start_extract,
194 .create_file = unix_create_file,
195 .create_directory = unix_create_directory,
196 .create_hardlink = unix_create_hardlink,
197 .create_symlink = unix_create_symlink,
198 .extract_unnamed_stream = unix_extract_unnamed_stream,
199 .set_unix_data = unix_set_unix_data,
200 .set_timestamps = unix_set_timestamps,
202 .path_separator = '/',
203 .path_max = PATH_MAX,
205 .requires_target_in_paths = 1,
206 .supports_case_sensitive_filenames = 1,
209 #endif /* !__WIN32__ */