Are two subdirectories with the same root guaranteed to be on the same mounted file system?

Clash Royale CLAN TAG#URR8PPP
up vote
5
down vote
favorite
A cpp file I'm working with creates a directory, i.e. mkdir( path, ... ), where path comes from an environment variable (e.g. getenv( "FOO" );).
As an example, say $FOO is /foo, and path, created above, is `/foo/newPath/'.
For my question scenario, it is possible that /foo/oldPath/ exists and has content (assume no further subdirectories), in which case I want to move files from /foo/oldPath/ to /foo/newPath.
My question is: because /foo/newPath/ is created as a subdirectory of $FOO, i.e. /foo/newPath/ and /foo/oldPath/ have the same parent directory, is it then guaranteed that both directories are on the same "mounted file system"? My understanding of mount points and file systems on Linux is tenuous at best.
The context behind this question is: if /foo/newPath/ and /foo/oldPath/ are guaranteed to be on the same mounted file system, I can use rename() to more easily perform the file movement than other alternatives. The man page of the function says that it will fail if oldPath and newPath are not on the same "mounted file system."
linux filesystems mount rename
add a comment |Â
up vote
5
down vote
favorite
A cpp file I'm working with creates a directory, i.e. mkdir( path, ... ), where path comes from an environment variable (e.g. getenv( "FOO" );).
As an example, say $FOO is /foo, and path, created above, is `/foo/newPath/'.
For my question scenario, it is possible that /foo/oldPath/ exists and has content (assume no further subdirectories), in which case I want to move files from /foo/oldPath/ to /foo/newPath.
My question is: because /foo/newPath/ is created as a subdirectory of $FOO, i.e. /foo/newPath/ and /foo/oldPath/ have the same parent directory, is it then guaranteed that both directories are on the same "mounted file system"? My understanding of mount points and file systems on Linux is tenuous at best.
The context behind this question is: if /foo/newPath/ and /foo/oldPath/ are guaranteed to be on the same mounted file system, I can use rename() to more easily perform the file movement than other alternatives. The man page of the function says that it will fail if oldPath and newPath are not on the same "mounted file system."
linux filesystems mount rename
add a comment |Â
up vote
5
down vote
favorite
up vote
5
down vote
favorite
A cpp file I'm working with creates a directory, i.e. mkdir( path, ... ), where path comes from an environment variable (e.g. getenv( "FOO" );).
As an example, say $FOO is /foo, and path, created above, is `/foo/newPath/'.
For my question scenario, it is possible that /foo/oldPath/ exists and has content (assume no further subdirectories), in which case I want to move files from /foo/oldPath/ to /foo/newPath.
My question is: because /foo/newPath/ is created as a subdirectory of $FOO, i.e. /foo/newPath/ and /foo/oldPath/ have the same parent directory, is it then guaranteed that both directories are on the same "mounted file system"? My understanding of mount points and file systems on Linux is tenuous at best.
The context behind this question is: if /foo/newPath/ and /foo/oldPath/ are guaranteed to be on the same mounted file system, I can use rename() to more easily perform the file movement than other alternatives. The man page of the function says that it will fail if oldPath and newPath are not on the same "mounted file system."
linux filesystems mount rename
A cpp file I'm working with creates a directory, i.e. mkdir( path, ... ), where path comes from an environment variable (e.g. getenv( "FOO" );).
As an example, say $FOO is /foo, and path, created above, is `/foo/newPath/'.
For my question scenario, it is possible that /foo/oldPath/ exists and has content (assume no further subdirectories), in which case I want to move files from /foo/oldPath/ to /foo/newPath.
My question is: because /foo/newPath/ is created as a subdirectory of $FOO, i.e. /foo/newPath/ and /foo/oldPath/ have the same parent directory, is it then guaranteed that both directories are on the same "mounted file system"? My understanding of mount points and file systems on Linux is tenuous at best.
The context behind this question is: if /foo/newPath/ and /foo/oldPath/ are guaranteed to be on the same mounted file system, I can use rename() to more easily perform the file movement than other alternatives. The man page of the function says that it will fail if oldPath and newPath are not on the same "mounted file system."
linux filesystems mount rename
edited May 8 at 18:49
asked May 3 at 20:13
StoneThrow
387313
387313
add a comment |Â
add a comment |Â
3 Answers
3
active
oldest
votes
up vote
13
down vote
accepted
They are not guaranteed that. It is possible that /foo/oldPath is a mount point.
This can, however, be easily checked by running mount | grep 'on /foo/oldPath'
No output should indicate that the oldPath directory is not a mount point.
You will need to be more careful if you are using nested directories, since you can have a mount point anywhere.
I'm not sure whether this is automated, but it's worth noting that the 3rd field from mount (space-separated) is the mount point for each line, so utilizing an cut -d ' ' -f 3 could be used to extract the path (should you need to verify it's not just a substring of another mount point, like /foo/oldPath/nested/mountPoint)
If you'd like to translate this into C/C++ code, you may be able to use system("mount | grep 'on /foo/oldPath'"), but I won't swear by that. You may have better luck on StackOverflow for more implementation detail there if you need it.
There's also themountpointcommand that's specifically for this, not that I recommend doing this with a command from C/C++.
â JoL
May 4 at 0:37
1
Note that it is also possible for two filesystems to be mounted onto the same directory. @sourcejedi mentions overlayfs in his answer. On some unixen there is also unionfs. So even ifoldPathis not a mount point it is not guaranteed to be on the same filesystem asnewPath
â slebetman
May 4 at 2:47
7
A better way to check for different file systems is to compare thest_devattribute of the return values of the respective*stat(2)calls. Alternativelyrename(2)will simply fail withEXDEVfor source and target files on different file systems.
â David Foerster
May 4 at 5:28
2
Also, thesystem()Isn't recommended stackoverflow.com/q/19913446/3701431
â Sergiy Kolodyazhnyy
May 4 at 5:58
1
You forgot that directory names can contain spaces.
â Emil Vikström
May 4 at 8:06
 |Â
show 1 more comment
up vote
5
down vote
You shouldnâÂÂt attempt this, for a variety of reasons (detailed in the other answers): /foo/oldPath could itself be a mountpoint, or an overlay file system could be present and prevent moving files. You can even encounter bind mounts, on single files, which will also cause problems when renaming files.
Instead of trying to determine ahead of time whether the files can be renamed, you should try to rename them and deal with the errors. rename will return -1 if an error occurs, and errno will be set to EXDEV if the rename isnâÂÂt possible because of cross-mount issues. You can then proceed in another fashion (copy and delete).
In general, to determine whether two file system objects are on the same file system, you should run stat on them and look at the device identifier (the st_dev field in struct stat). Two file system objects on the same file system will have the same device identifier.
add a comment |Â
up vote
4
down vote
Note that when you run on overlayfs, you cannot rely on rename() of pre-existing directories.
I think you could usually ignore this possibility, if you're not writing a general purpose file management tool... For example, a package manager... in which case you apparently might not consider it fixable (for atomicity reasons) and want to rely on the new redirect_dir format of overlayfs.
So this is more a pedantic note to let you know this is Linux, we don't comply with POSIX if we don't want to, and "guaranteed" is a very strong word :).
https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
Unless "redirect_dir" feature is enabled, rename(2) on a lower or merged
directory will fail with EXDEV.
Overlayfs already does not match usual expectations of a unix filesystem in other details:
Objects that are not directories (files, symlinks, device-special
files etc.) are presented either from the upper or lower filesystem as
appropriate. When a file in the lower filesystem is accessed in a way
the requires write-access, such as opening for write access, changing
some metadata etc., the file is first copied from the lower filesystem
to the upper filesystem (copy_up)...
The copy_up operation essentially creates a new, identical file and
moves it over to the old name. Any open files referring to this inode
will access the old data.
add a comment |Â
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
13
down vote
accepted
They are not guaranteed that. It is possible that /foo/oldPath is a mount point.
This can, however, be easily checked by running mount | grep 'on /foo/oldPath'
No output should indicate that the oldPath directory is not a mount point.
You will need to be more careful if you are using nested directories, since you can have a mount point anywhere.
I'm not sure whether this is automated, but it's worth noting that the 3rd field from mount (space-separated) is the mount point for each line, so utilizing an cut -d ' ' -f 3 could be used to extract the path (should you need to verify it's not just a substring of another mount point, like /foo/oldPath/nested/mountPoint)
If you'd like to translate this into C/C++ code, you may be able to use system("mount | grep 'on /foo/oldPath'"), but I won't swear by that. You may have better luck on StackOverflow for more implementation detail there if you need it.
There's also themountpointcommand that's specifically for this, not that I recommend doing this with a command from C/C++.
â JoL
May 4 at 0:37
1
Note that it is also possible for two filesystems to be mounted onto the same directory. @sourcejedi mentions overlayfs in his answer. On some unixen there is also unionfs. So even ifoldPathis not a mount point it is not guaranteed to be on the same filesystem asnewPath
â slebetman
May 4 at 2:47
7
A better way to check for different file systems is to compare thest_devattribute of the return values of the respective*stat(2)calls. Alternativelyrename(2)will simply fail withEXDEVfor source and target files on different file systems.
â David Foerster
May 4 at 5:28
2
Also, thesystem()Isn't recommended stackoverflow.com/q/19913446/3701431
â Sergiy Kolodyazhnyy
May 4 at 5:58
1
You forgot that directory names can contain spaces.
â Emil Vikström
May 4 at 8:06
 |Â
show 1 more comment
up vote
13
down vote
accepted
They are not guaranteed that. It is possible that /foo/oldPath is a mount point.
This can, however, be easily checked by running mount | grep 'on /foo/oldPath'
No output should indicate that the oldPath directory is not a mount point.
You will need to be more careful if you are using nested directories, since you can have a mount point anywhere.
I'm not sure whether this is automated, but it's worth noting that the 3rd field from mount (space-separated) is the mount point for each line, so utilizing an cut -d ' ' -f 3 could be used to extract the path (should you need to verify it's not just a substring of another mount point, like /foo/oldPath/nested/mountPoint)
If you'd like to translate this into C/C++ code, you may be able to use system("mount | grep 'on /foo/oldPath'"), but I won't swear by that. You may have better luck on StackOverflow for more implementation detail there if you need it.
There's also themountpointcommand that's specifically for this, not that I recommend doing this with a command from C/C++.
â JoL
May 4 at 0:37
1
Note that it is also possible for two filesystems to be mounted onto the same directory. @sourcejedi mentions overlayfs in his answer. On some unixen there is also unionfs. So even ifoldPathis not a mount point it is not guaranteed to be on the same filesystem asnewPath
â slebetman
May 4 at 2:47
7
A better way to check for different file systems is to compare thest_devattribute of the return values of the respective*stat(2)calls. Alternativelyrename(2)will simply fail withEXDEVfor source and target files on different file systems.
â David Foerster
May 4 at 5:28
2
Also, thesystem()Isn't recommended stackoverflow.com/q/19913446/3701431
â Sergiy Kolodyazhnyy
May 4 at 5:58
1
You forgot that directory names can contain spaces.
â Emil Vikström
May 4 at 8:06
 |Â
show 1 more comment
up vote
13
down vote
accepted
up vote
13
down vote
accepted
They are not guaranteed that. It is possible that /foo/oldPath is a mount point.
This can, however, be easily checked by running mount | grep 'on /foo/oldPath'
No output should indicate that the oldPath directory is not a mount point.
You will need to be more careful if you are using nested directories, since you can have a mount point anywhere.
I'm not sure whether this is automated, but it's worth noting that the 3rd field from mount (space-separated) is the mount point for each line, so utilizing an cut -d ' ' -f 3 could be used to extract the path (should you need to verify it's not just a substring of another mount point, like /foo/oldPath/nested/mountPoint)
If you'd like to translate this into C/C++ code, you may be able to use system("mount | grep 'on /foo/oldPath'"), but I won't swear by that. You may have better luck on StackOverflow for more implementation detail there if you need it.
They are not guaranteed that. It is possible that /foo/oldPath is a mount point.
This can, however, be easily checked by running mount | grep 'on /foo/oldPath'
No output should indicate that the oldPath directory is not a mount point.
You will need to be more careful if you are using nested directories, since you can have a mount point anywhere.
I'm not sure whether this is automated, but it's worth noting that the 3rd field from mount (space-separated) is the mount point for each line, so utilizing an cut -d ' ' -f 3 could be used to extract the path (should you need to verify it's not just a substring of another mount point, like /foo/oldPath/nested/mountPoint)
If you'd like to translate this into C/C++ code, you may be able to use system("mount | grep 'on /foo/oldPath'"), but I won't swear by that. You may have better luck on StackOverflow for more implementation detail there if you need it.
edited May 3 at 20:30
answered May 3 at 20:17
cunninghamp3
473215
473215
There's also themountpointcommand that's specifically for this, not that I recommend doing this with a command from C/C++.
â JoL
May 4 at 0:37
1
Note that it is also possible for two filesystems to be mounted onto the same directory. @sourcejedi mentions overlayfs in his answer. On some unixen there is also unionfs. So even ifoldPathis not a mount point it is not guaranteed to be on the same filesystem asnewPath
â slebetman
May 4 at 2:47
7
A better way to check for different file systems is to compare thest_devattribute of the return values of the respective*stat(2)calls. Alternativelyrename(2)will simply fail withEXDEVfor source and target files on different file systems.
â David Foerster
May 4 at 5:28
2
Also, thesystem()Isn't recommended stackoverflow.com/q/19913446/3701431
â Sergiy Kolodyazhnyy
May 4 at 5:58
1
You forgot that directory names can contain spaces.
â Emil Vikström
May 4 at 8:06
 |Â
show 1 more comment
There's also themountpointcommand that's specifically for this, not that I recommend doing this with a command from C/C++.
â JoL
May 4 at 0:37
1
Note that it is also possible for two filesystems to be mounted onto the same directory. @sourcejedi mentions overlayfs in his answer. On some unixen there is also unionfs. So even ifoldPathis not a mount point it is not guaranteed to be on the same filesystem asnewPath
â slebetman
May 4 at 2:47
7
A better way to check for different file systems is to compare thest_devattribute of the return values of the respective*stat(2)calls. Alternativelyrename(2)will simply fail withEXDEVfor source and target files on different file systems.
â David Foerster
May 4 at 5:28
2
Also, thesystem()Isn't recommended stackoverflow.com/q/19913446/3701431
â Sergiy Kolodyazhnyy
May 4 at 5:58
1
You forgot that directory names can contain spaces.
â Emil Vikström
May 4 at 8:06
There's also the
mountpoint command that's specifically for this, not that I recommend doing this with a command from C/C++.â JoL
May 4 at 0:37
There's also the
mountpoint command that's specifically for this, not that I recommend doing this with a command from C/C++.â JoL
May 4 at 0:37
1
1
Note that it is also possible for two filesystems to be mounted onto the same directory. @sourcejedi mentions overlayfs in his answer. On some unixen there is also unionfs. So even if
oldPath is not a mount point it is not guaranteed to be on the same filesystem as newPathâ slebetman
May 4 at 2:47
Note that it is also possible for two filesystems to be mounted onto the same directory. @sourcejedi mentions overlayfs in his answer. On some unixen there is also unionfs. So even if
oldPath is not a mount point it is not guaranteed to be on the same filesystem as newPathâ slebetman
May 4 at 2:47
7
7
A better way to check for different file systems is to compare the
st_dev attribute of the return values of the respective *stat(2) calls. Alternatively rename(2) will simply fail with EXDEV for source and target files on different file systems.â David Foerster
May 4 at 5:28
A better way to check for different file systems is to compare the
st_dev attribute of the return values of the respective *stat(2) calls. Alternatively rename(2) will simply fail with EXDEV for source and target files on different file systems.â David Foerster
May 4 at 5:28
2
2
Also, the
system() Isn't recommended stackoverflow.com/q/19913446/3701431â Sergiy Kolodyazhnyy
May 4 at 5:58
Also, the
system() Isn't recommended stackoverflow.com/q/19913446/3701431â Sergiy Kolodyazhnyy
May 4 at 5:58
1
1
You forgot that directory names can contain spaces.
â Emil Vikström
May 4 at 8:06
You forgot that directory names can contain spaces.
â Emil Vikström
May 4 at 8:06
 |Â
show 1 more comment
up vote
5
down vote
You shouldnâÂÂt attempt this, for a variety of reasons (detailed in the other answers): /foo/oldPath could itself be a mountpoint, or an overlay file system could be present and prevent moving files. You can even encounter bind mounts, on single files, which will also cause problems when renaming files.
Instead of trying to determine ahead of time whether the files can be renamed, you should try to rename them and deal with the errors. rename will return -1 if an error occurs, and errno will be set to EXDEV if the rename isnâÂÂt possible because of cross-mount issues. You can then proceed in another fashion (copy and delete).
In general, to determine whether two file system objects are on the same file system, you should run stat on them and look at the device identifier (the st_dev field in struct stat). Two file system objects on the same file system will have the same device identifier.
add a comment |Â
up vote
5
down vote
You shouldnâÂÂt attempt this, for a variety of reasons (detailed in the other answers): /foo/oldPath could itself be a mountpoint, or an overlay file system could be present and prevent moving files. You can even encounter bind mounts, on single files, which will also cause problems when renaming files.
Instead of trying to determine ahead of time whether the files can be renamed, you should try to rename them and deal with the errors. rename will return -1 if an error occurs, and errno will be set to EXDEV if the rename isnâÂÂt possible because of cross-mount issues. You can then proceed in another fashion (copy and delete).
In general, to determine whether two file system objects are on the same file system, you should run stat on them and look at the device identifier (the st_dev field in struct stat). Two file system objects on the same file system will have the same device identifier.
add a comment |Â
up vote
5
down vote
up vote
5
down vote
You shouldnâÂÂt attempt this, for a variety of reasons (detailed in the other answers): /foo/oldPath could itself be a mountpoint, or an overlay file system could be present and prevent moving files. You can even encounter bind mounts, on single files, which will also cause problems when renaming files.
Instead of trying to determine ahead of time whether the files can be renamed, you should try to rename them and deal with the errors. rename will return -1 if an error occurs, and errno will be set to EXDEV if the rename isnâÂÂt possible because of cross-mount issues. You can then proceed in another fashion (copy and delete).
In general, to determine whether two file system objects are on the same file system, you should run stat on them and look at the device identifier (the st_dev field in struct stat). Two file system objects on the same file system will have the same device identifier.
You shouldnâÂÂt attempt this, for a variety of reasons (detailed in the other answers): /foo/oldPath could itself be a mountpoint, or an overlay file system could be present and prevent moving files. You can even encounter bind mounts, on single files, which will also cause problems when renaming files.
Instead of trying to determine ahead of time whether the files can be renamed, you should try to rename them and deal with the errors. rename will return -1 if an error occurs, and errno will be set to EXDEV if the rename isnâÂÂt possible because of cross-mount issues. You can then proceed in another fashion (copy and delete).
In general, to determine whether two file system objects are on the same file system, you should run stat on them and look at the device identifier (the st_dev field in struct stat). Two file system objects on the same file system will have the same device identifier.
answered May 4 at 8:33
Stephen Kitt
140k22302363
140k22302363
add a comment |Â
add a comment |Â
up vote
4
down vote
Note that when you run on overlayfs, you cannot rely on rename() of pre-existing directories.
I think you could usually ignore this possibility, if you're not writing a general purpose file management tool... For example, a package manager... in which case you apparently might not consider it fixable (for atomicity reasons) and want to rely on the new redirect_dir format of overlayfs.
So this is more a pedantic note to let you know this is Linux, we don't comply with POSIX if we don't want to, and "guaranteed" is a very strong word :).
https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
Unless "redirect_dir" feature is enabled, rename(2) on a lower or merged
directory will fail with EXDEV.
Overlayfs already does not match usual expectations of a unix filesystem in other details:
Objects that are not directories (files, symlinks, device-special
files etc.) are presented either from the upper or lower filesystem as
appropriate. When a file in the lower filesystem is accessed in a way
the requires write-access, such as opening for write access, changing
some metadata etc., the file is first copied from the lower filesystem
to the upper filesystem (copy_up)...
The copy_up operation essentially creates a new, identical file and
moves it over to the old name. Any open files referring to this inode
will access the old data.
add a comment |Â
up vote
4
down vote
Note that when you run on overlayfs, you cannot rely on rename() of pre-existing directories.
I think you could usually ignore this possibility, if you're not writing a general purpose file management tool... For example, a package manager... in which case you apparently might not consider it fixable (for atomicity reasons) and want to rely on the new redirect_dir format of overlayfs.
So this is more a pedantic note to let you know this is Linux, we don't comply with POSIX if we don't want to, and "guaranteed" is a very strong word :).
https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
Unless "redirect_dir" feature is enabled, rename(2) on a lower or merged
directory will fail with EXDEV.
Overlayfs already does not match usual expectations of a unix filesystem in other details:
Objects that are not directories (files, symlinks, device-special
files etc.) are presented either from the upper or lower filesystem as
appropriate. When a file in the lower filesystem is accessed in a way
the requires write-access, such as opening for write access, changing
some metadata etc., the file is first copied from the lower filesystem
to the upper filesystem (copy_up)...
The copy_up operation essentially creates a new, identical file and
moves it over to the old name. Any open files referring to this inode
will access the old data.
add a comment |Â
up vote
4
down vote
up vote
4
down vote
Note that when you run on overlayfs, you cannot rely on rename() of pre-existing directories.
I think you could usually ignore this possibility, if you're not writing a general purpose file management tool... For example, a package manager... in which case you apparently might not consider it fixable (for atomicity reasons) and want to rely on the new redirect_dir format of overlayfs.
So this is more a pedantic note to let you know this is Linux, we don't comply with POSIX if we don't want to, and "guaranteed" is a very strong word :).
https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
Unless "redirect_dir" feature is enabled, rename(2) on a lower or merged
directory will fail with EXDEV.
Overlayfs already does not match usual expectations of a unix filesystem in other details:
Objects that are not directories (files, symlinks, device-special
files etc.) are presented either from the upper or lower filesystem as
appropriate. When a file in the lower filesystem is accessed in a way
the requires write-access, such as opening for write access, changing
some metadata etc., the file is first copied from the lower filesystem
to the upper filesystem (copy_up)...
The copy_up operation essentially creates a new, identical file and
moves it over to the old name. Any open files referring to this inode
will access the old data.
Note that when you run on overlayfs, you cannot rely on rename() of pre-existing directories.
I think you could usually ignore this possibility, if you're not writing a general purpose file management tool... For example, a package manager... in which case you apparently might not consider it fixable (for atomicity reasons) and want to rely on the new redirect_dir format of overlayfs.
So this is more a pedantic note to let you know this is Linux, we don't comply with POSIX if we don't want to, and "guaranteed" is a very strong word :).
https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
Unless "redirect_dir" feature is enabled, rename(2) on a lower or merged
directory will fail with EXDEV.
Overlayfs already does not match usual expectations of a unix filesystem in other details:
Objects that are not directories (files, symlinks, device-special
files etc.) are presented either from the upper or lower filesystem as
appropriate. When a file in the lower filesystem is accessed in a way
the requires write-access, such as opening for write access, changing
some metadata etc., the file is first copied from the lower filesystem
to the upper filesystem (copy_up)...
The copy_up operation essentially creates a new, identical file and
moves it over to the old name. Any open files referring to this inode
will access the old data.
answered May 3 at 21:07
sourcejedi
18.2k32475
18.2k32475
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f441652%2fare-two-subdirectories-with-the-same-root-guaranteed-to-be-on-the-same-mounted-f%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password